Есть ли какая-либо причина использовать WaitHandle вместо bool для пометки отмены? - PullRequest
3 голосов
/ 22 марта 2011

Я унаследовал немного многопоточного кода, и после его просмотра я нахожу структуры, подобные этой (в методе фонового потока):

private ManualResetEvent stopEvent = new ManualResetEvent(false);

private void Run_Thread() {
    while (!stopEvent.WaitOne(0, true)) {
        // code here
    }
}

Обычно существует публичный или приватный Stop() метод, например:

public void Stop() {
    stopEvent.Set();
    bgThread.Join();
}

Мой вопрос таков: что обслуживается здесь при помощи дескриптора ожидания? Кажется, что это сделано для того, чтобы сигнализация об остановке была атомарной операцией, но я думал, что запись в логическое значение в любом случае была атомарной. Если это так, есть ли причина не просто использовать следующее:

private void Run_Thread() {
    while(!stop) {
        // code here
    }
}

public void Stop() { 
    stop = true;
    bgThread.Join();
}

Ответы [ 3 ]

7 голосов
/ 22 марта 2011

Запись в переменную bool действительно атомарна, но если переменная также не volatile (или вы вводите какую-то другую синхронизацию), то она может быть не видна из других потоков.Такие проблемы трудно отследить и воспроизвести.

Например, на моем ноутбуке x64 следующая программа корректно останавливается.На моем нетбуке x86 он висит вечно.(Оба скомпилированы с csc /o+ Test.cs).

using System;
using System.Threading;

class Test
{
    static bool stop = false;

    static void Main(string[] args)
    {
        new Thread(CountLots).Start();
        Thread.Sleep(100);
        stop = true;
        Console.WriteLine("Finished...");
    }    

    static void CountLots()
    {
        long total = 0;
        while (!stop)
        {
            total++;
        }
    }
}

В этом конкретном случае кажется разумным использовать флаг volatile - хотя, если вы используете .NET 4, было бы лучше использовать механизмы отмены задач:)

Конечно, обычно лучшая причина для использования чего-либо, кроме флага, это если вы хотите подождать какое-то условие - будь то "есть новый элемент" или "я был отменен" (или оба) - без зацикливания.

1 голос
/ 22 марта 2011

Простое использование bool не сработает, вы должны объявить его volatile , чтобы сообщить генератору кода, что он не должен сохранять значение в регистре процессора.Точное время, когда поток увидит значение, установленное в true, непредсказуемо, оно сильно зависит от типа процессора, на котором работает ваш код.

Уродливые детали, которые вы можете игнорировать при использовании WaitHandle.

Последний аргумент должен быть False, кстати.

1 голос
/ 22 марта 2011

Вы не можете сделать контролируемое / блокирующее «ожидание» для bool (хотя, вероятно, вам это и не нужно, и Monitor может быть более легким в любом случае).

В качестве отмены flag bool - это нормально, но вы можете захотеть сделать bool volatile, чтобы избежать проблем с кэшем регистров.

...