Никогда, никогда не используйте Thread.Suspend
. Основная проблема заключается в том, что в 99% случаев вы не можете знать, что делает этот поток, когда приостанавливаете его. Если этот поток удерживает блокировку, вы облегчаете попадание в тупиковую ситуацию и т. Д. Помните, что код, который вы вызываете, может получать / снимать блокировки за кулисами. Win32 имеет похожий API: SuspendThread
и ResumeThread
. Следующие документы для SuspendThread
дают хорошее резюме опасностей API:
http://msdn.microsoft.com/en-us/library/ms686345(VS.85).aspx
Эта функция в первую очередь предназначена для использования отладчиками. Он не предназначен для синхронизации потоков. Вызов SuspendThread для потока, которому принадлежит объект синхронизации, такой как мьютекс или критическая секция, может привести к тупиковой ситуации, если вызывающий поток попытается получить объект синхронизации, принадлежащий приостановленному потоку. Чтобы избежать этой ситуации, поток в приложении, который не является отладчиком, должен сигнализировать другому потоку о приостановке. Целевой поток должен быть спроектирован так, чтобы отслеживать этот сигнал и реагировать соответствующим образом.
Правильный способ приостановить поток на неопределенный срок - использовать ManualResetEvent
. Поток скорее всего зацикливается, выполняя некоторую работу. Самый простой способ приостановить поток - это заставить поток «проверять» событие на каждой итерации, например:
while (true)
{
_suspendEvent.WaitOne(Timeout.Infinite);
// Do some work...
}
Вы указываете бесконечное время ожидания, поэтому, когда событие не сигнализируется, поток блокируется на неопределенный срок, пока событие не будет сигнализировано, и в этот момент поток возобновит работу с того места, где он остановился.
Вы бы создали событие так:
ManualResetEvent _suspendEvent = new ManualResetEvent(true);
Параметр true
указывает событию начинаться в сигнальном состоянии.
Если вы хотите приостановить поток, вы делаете следующее:
_suspendEvent.Reset();
А для возобновления темы:
_suspendEvent.Set();
Вы можете использовать аналогичный механизм, чтобы сигнализировать потоку о завершении и ожидании обоих событий, определяя, какое событие было сигнализировано.
Ради интереса приведу полный пример:
public class Worker
{
ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
ManualResetEvent _pauseEvent = new ManualResetEvent(true);
Thread _thread;
public Worker() { }
public void Start()
{
_thread = new Thread(DoWork);
_thread.Start();
}
public void Pause()
{
_pauseEvent.Reset();
}
public void Resume()
{
_pauseEvent.Set();
}
public void Stop()
{
// Signal the shutdown event
_shutdownEvent.Set();
// Make sure to resume any paused threads
_pauseEvent.Set();
// Wait for the thread to exit
_thread.Join();
}
public void DoWork()
{
while (true)
{
_pauseEvent.WaitOne(Timeout.Infinite);
if (_shutdownEvent.WaitOne(0))
break;
// Do the work here..
}
}
}