Как заставить фоновый поток приостановиться, а затем продолжить при нажатии кнопки? - PullRequest
3 голосов
/ 23 декабря 2009

У меня есть форма Windows и класс с двумя простыми методами, которые выполняются рекурсивно недетерминированным способом (это означает, что неизвестно, какая рекурсия будет вызываться, обе могут вызывать другие) ... Теперь во время этого есть некоторые моменты рекурсия, при которой я хочу приостановить выполнение и подождать, пока пользователь нажмет кнопку «Следующий шаг». Только после нажатия кнопки рекурсивные функции могут продолжаться. Класс работает в отдельном потоке, поэтому он не блокирует пользовательский интерфейс.

Во время этой паузы Форма просто получит значение из класса и отобразит его в списке. Затем после нажатия кнопки рекурсия продолжается до следующей паузы (). Мне это нужно, чтобы пользователь мог шаг за шагом увидеть, что происходит в рекурсии. Также мне нужно иметь возможность поставить Pause () в любом месте рекурсивного метода (даже несколько раз), не вызывая побочных эффектов ...

Единственный способ, который мне приходит в голову, - это вызвать метод Pause (), в котором цикл проверяет какой-то заблокированный флаг и затем некоторое время спит (кнопка затем установит флаг), но у меня были некоторые неудачные опыты с Thread .Sleep () в Windows Forms (блокировка интерфейса), поэтому я смотрю на другие варианты.

Есть ли какой-нибудь чистый способ сделать это?

Ответы [ 3 ]

6 голосов
/ 23 декабря 2009

Используйте ManualResetEvent, который инициализирован на true, поэтому он начинает устанавливаться. В известном месте того или иного метода (или обоих) дождитесь события. В большинстве случаев событие будет установлено, поэтому фоновый поток будет продолжен немедленно. Однако когда пользователь нажимает кнопку Пауза, сбрасывает событие, в результате чего фоновый поток блокируется при следующем достижении события. Когда пользователь нажимает кнопку «Продолжить», устанавливает событие, позволяя фоновому потоку продолжить снова.

Нет никаких причин, по которым поток пользовательского интерфейса должен блокироваться в этом сценарии.

2 голосов
/ 23 декабря 2009

Использовать объект AutoResetEvent.

Вызовите метод .WaitOne для него из вашего потока, чтобы приостановить его, и вызовите метод .Set для него из вашей кнопки, чтобы отменить его.

1 голос
/ 23 декабря 2009

Это хорошее место для использования Mutex нестандартным способом. Просто заставьте свой фоновый поток взять и отпустить Mutex, когда он будет в том положении, когда его можно ждать.

Попросите ваш поток графического интерфейса взять Mutex, когда он хочет заблокировать фоновый поток, и освободить его, когда он сможет работать.

Таким образом, фоновый поток будет ждать, когда он должен, и будет просто включаться и выключаться из Mutex, когда ему позволят работать.

Думайте о «праве на запуск» как о ресурсе, который защищает критическая секция.

как это

// this object has to be visible to both threads
System.Threading.Mutex mtx = new Mutex();

// worker thread does this wherever it's ok for it to pause
mtx.WaitOne();
mtx.ReleaseMutex();

// main thread does this to pause the worker
Mtx.WaitOne();

// main thread does this this to unpause it.
mtx.ReleaseMutex();
...