Расширение PDE от Andrew Richards добавляет команду !busy
!busy - Equivalent of ~*knL but only displays stacks that are at least
'depth' frames deep (default depth is 1) and are not waiting for:-
~ ntdll!NtWaitFor*
~ ntdll!ZwWaitFor*
~ ntdll!NtRemoveIoCompletion
~ ntdll!ZwRemoveIoCompletion
~ ntdll!NtReplyWaitReceivePort
~ ntdll!ZwReplyWaitReceivePortEx
Проблематично найти для нее загрузку, но вы можете пропинговать Andrew по каналу Channel 9. Он обычно отвечает довольно быстро.
Критический раздел кода является тем, который может только быть выполнен одним потоком за один раз. Возьмите сервер чата, например. Если у Вас есть поток для каждого соединения (т.е. каждый конечный пользователь), один "критический раздел" является кодом буферизации (отправляющий входящее сообщение всем клиентам). Если больше чем один поток попытается буферизовать сообщение сразу, то Вы переплетите BfrIToS mANtwD PIoEmesCEsaSges, который очевидно бесполезен вообще.
Блокировка - что-то, что может использоваться для синхронизации доступа к критическому разделу (или ресурсы в целом). В нашем примере сервера чата блокировка похожа на заблокированную комнату с печатающим устройством в нем. Если один поток там (для вывода сообщения), никакой другой поток не может войти в комнату. После того как первый поток сделан, он разблокировал комнату и листы. Затем другой поток может войти в комнату (блокирующий его). "Aquiring" блокировка просто означает, "Что я получаю комнату".
"Критический раздел" является блоком кода, в котором, для правильности, необходимо гарантировать, что только один поток управления может быть в том разделе за один раз. В целом Вам нужен критический раздел для содержания ссылок, которые пишут значения в память, которая может быть общей для больше чем один параллельный процесс.
Другие люди дали очень хорошие определения. Вот классический пример:
import threading
account_balance = 0 # The "resource" that zenazn mentions.
account_balance_lock = threading.Lock()
def change_account_balance(delta):
global account_balance
with account_balance_lock:
# Critical section is within this block.
account_balance += delta
Скажем, то, что +=
оператор состоит из трех субкомпонентов:
Если Вы не имеете with account_balance_lock
оператор и Вы выполняетесь два change_account_balance
вызовы параллельно можно закончить тем, что чередовали три операции субкомпонента опасным способом. Скажем, Вы одновременно звоните change_account_balance(100)
(Иначе на месте продажи) и change_account_balance(-100)
(Иначе отрицательный). Это могло произойти:
pos = threading.Thread(target=change_account_balance, args=[100])
neg = threading.Thread(target=change_account_balance, args=[-100])
pos.start(), neg.start()
Поскольку Вы не вынудили операции произойти в дискретных блоках, у Вас может быть три возможных результата (-100, 0, 100).
with [lock]
оператор является единственной, неделимой операцией, которая говорит, "Позвольте меня быть единственным потоком, выполняющим этот блок кода. Если что-то еще выполняется, это прохладно - я буду ожидать". Это гарантирует что обновления account_balance
"ориентирован на многопотоковое исполнение" (безопасный от параллелизма).
Примечание: Существует протест к этой схеме: необходимо не забыть получать account_balance_lock
(через with
) каждый раз Вы хотите управлять account_balance
чтобы код остался ориентированным на многопотоковое исполнение. Существуют способы сделать это менее хрупким, но это - ответ на целый другой вопрос.
Править: Ретроспективно, вероятно, важно упомянуть что with
оператор неявно называет блокирование acquire
на блокировке - это, "я буду ожидать" часть вышеупомянутого диалогового окна потока. Напротив, неблокирование получают, говорит, "Если я не могу получить блокировку сразу же, сообщите мне" и затем полагайтесь на Вас, чтобы проверить, получили ли Вы блокировку или нет.
import logging # This module is thread safe.
import threading
LOCK = threading.Lock()
def run():
if LOCK.acquire(False): # Non-blocking -- return whether we got it
logging.info('Got the lock!')
LOCK.release()
else:
logging.info("Couldn't get the lock. Maybe next time")
logging.basicConfig(level=logging.INFO)
threads = [threading.Thread(target=run) for i in range(100)]
for thread in threads:
thread.start()
Я также хочу добавить, что основная цель блокировки состоит в том, чтобы гарантировать атомарность приобретения (неделимость acquire
через потоки), который не гарантирует простой булев флаг. Семантика атомарных операций является, вероятно, также содержанием другого вопроса.