Я понимаю, что при разработке многопоточных приложений вы должны синхронизировать доступ к общей памяти, используя либо, например, монитор, либо блокировку.
Как вы сообщаете процессу ожидания (proc2), что процесс, использующий заблокированный блок кода (proc1), завершил использование кода?
Вы говорите о реальных процессах операционной системы или просто о задачах в процессе?
Если это просто задачи внутри процесса, вы обычно просто позволяете блокировщикам выполнять эту работу за вас. Вторая задача пытается получить блокировку, которой владеет первая задача, и просто блокирует. Когда первая задача освобождает блокировку, вторая задача автоматически разблокируется.
Если вы хотите, чтобы второй поток имел возможность выполнять другую работу сначала, вы могли бы вместо этого использовать Monitor.TryEnter
- хотя это немного более странно.
Если вы хотите подождать, но у вас есть более сложные требования, чем просто блокировка, то, вероятно, требуется Monitor.Pulse/PulseAll/Wait
. Для примера см. Вторую половину эту страницу.
Если вы действительно говорите о процессах, вам необходимо использовать общесистемную структуру, такую как Mutex
. Они являются "более тяжелыми", чем встроенные мониторы .NET, но допускают координацию между процессами.
Другой процесс обычно блокируется, ожидая захвата блокировки. Когда ваш первый процесс освободит его, второй процесс может его захватить.
Другими словами, в типичном сценарии вы не "рассказываете" другому потоку, а не останавливаете его.
(Существуют сценарии, в которых вы хотите указать поток, который обычно обрабатывается с помощью AutoResetEvent или ManualResetEvent)
Для этого вам нужно использовать различные объекты синхронизации, доступные на С#. Некоторые примеры доступных объектов синхронизации: System.Threading.Mutex, System.Threading.Semaphore, System.Threading.ManualResetEvent и System.Threading.AutoResetEvent (это не исчерпывающий список, но это основы). Точный объект синхронизации, который вы хотите, зависит от ваших конкретных потребностей.
Мьютекс, вероятно, самый простой в использовании, поэтому я приведу его в качестве примера. Скажем, у меня есть две функции, которые работают в двух разных потоках (я буду придерживаться ваших собственных примеров, proc1 и proc2). Обе функции должны получить доступ к одной и той же переменной, foo. В каждой функции, которая обращается к foo, вам нужно сначала заблокировать ваш мьютекс. Затем сделайте все, что вам нужно, затем откройте его.
Например:
class bar
{
private int foo;
private System.Threading.Mutex lock = new System.Threading.Mutex;
public void proc1()
{
lock.WaitOne();
// do stuff to foo
lock.ReleaseMutex();
}
public void proc2()
{
lock.WaitOne();
// do stuff to foo
lock.ReleaseMutex();
}
};
С помощью этого метода будет выполняться proc1. Он попытается "схватить" мьютекс (замок). Если мьютекс уже захвачен, proc1 перейдет в спящий режим, пока мьютекс не будет "освобожден" другим потоком - proc1 будет сидеть и ждать, ничего не делать (и не есть циклов процессора!) До тех пор, пока мьютекс не будет выпущен. Затем он закроет его и сделает свое дело. Никакая другая нить не сможет захватить мьютекс до тех пор, пока proc1 не будет выполнен с ней.
Другой вариант - использовать событие. С# предоставляет два типа событий - ручной reset и авторешетку. Для моего примера я буду использовать руководство reset.
class bar
{
private System.Threading.ManualResetEvent event = new System.Threading.ManualResetEvent;
public void proc1()
{
// do stuff
event.Set();
}
public void proc2()
{
event.WaitOne();
event.Reset();
// do stuff
}
};
В этом примере, когда proc2 работает, он переходит в режим сна, когда он нажимает "event.WaitOne" и не использует циклы процессора, пока proc1 "не устанавливает" событие. Установка события заставляет proc2 просыпаться, и теперь он может сделать свое дело. Поскольку это ручной reset событие, событие будет оставаться в состоянии "set" до вызова event.Reset().
В зависимости от характера многопоточности Thread.Join может сделать трюк. Он блокирует вызывающий поток, пока поток не завершится, продолжая выполнять стандартную передачу сообщений.
Reset события особенно удобны для этого.
http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx