Пробуждение потока в C # - PullRequest
       18

Пробуждение потока в C #

1 голос
/ 07 октября 2011

Я ищу простой способ уложить нить в сон и разбудить ее. Поток работает в фоновом режиме в бесконечном цикле и иногда выполняет некоторую работу, иногда просто проходит. Я обнаружил, что нет соответствующего Wait () для Sleep () и пробуждение потока с помощью Interrupt () вызывает исключение. Видимо, спящая нить не предназначена для того, чтобы ее нарушать.
Поскольку я знаю, когда работа появляется, кажется хорошей идеей сообщить нить, вместо того, чтобы проверять ее снова и снова.

Как можно перевести поток в «более легкий сон», чтобы можно было просыпаться в одиночку каждую секунду или по команде другого потока?

//Thread to put to sleep and wake (thread1)
while (true)
{
    if (thereIsWork)
    { DoWork(); }
    //put thread to sleep in a way that other threads can wake it, and it wakes alone after some time (eg. 1000 ms)
    // Thread.Sleep(1000); //nice, but not working as desired
}

-

//Other thread:

thereIsWork = true;
//thread1.Wake(); //Not existing

Ответы [ 4 ]

4 голосов
/ 07 октября 2011

Вы можете использовать AutoResetEvent для этого - просто позвоните Set(), чтобы сообщить, что работа должна быть выполнена, и ваш поток ожидает ее вызова, используя WaitOne().

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

4 голосов
/ 07 октября 2011

Поток не должен Sleep(), он должен вызывать WaitOne() для AutoResetEvent или ManualResetEvent, пока какой-то другой поток не вызовет Set() для того же объекта повторного события.

1 голос
/ 07 октября 2011

Как насчет использования очереди блокировки с Monitor Pulse и Wait:

class BlockingQueue<T>
{
    private Queue<T> _queue = new Queue<T>();
    public void Enqueue(T data)
    {
        if (data == null) throw new ArgumentNullException("data");
        lock (_queue)
        {
            _queue.Enqueue(data);
            Monitor.Pulse(_queue);
        }
    }
    public T Dequeue()
    {
        lock (_queue)
        {
            while (_queue.Count == 0) Monitor.Wait(_queue);
            return _queue.Dequeue();
        }
    }
}

Тогда поток 1 становится

BlockingQueue<Action> _workQueue = new BlockingQueue<Action>();

while (true)
{
    var workItem = _workQueue.Dequeue();
    workItem();
}

И другой поток:

_workQueue.Enqueue(DoWork);

Примечание: вам, вероятно, следует использовать встроенный тип, если вы используете .Net 4 BlockingCollection , используя Add и Take вместо Enqueue и Dequeue.

Edit: Хорошо. Если вы хотите, это действительно просто ...

//Thread to put to sleep and wake (thread1)
while (true)
{
    lock(_lock)
    {
        while (!thereIsWork) Monitor.Wait(_lock);
        DoWork(); 
    }
    //put thread to sleep in a way that other threads can wake it, and it wakes alone after some time (eg. 1000 ms)
    // Thread.Sleep(1000); //nice, but not working as desired
}

и

//Other thread:
lock(_lock)
{
    thereIsWork = true;
    //thread1.Wake(); //Not existing
    Monitor.Pulse(_lock);
}
0 голосов
/ 07 октября 2011

Я не специалист по потокам, но, возможно, вам нужен EventWaitHandle. Проверьте эту ссылку

...