Почему делают потоки, ожидающие на ManualResetEvent, продолжают ожидать, даже когда Близко () назван?

Мы были удивлены узнать сегодня что потоки, ожидающие на a ManualResetEvent продолжите ожидать на событии, даже когда оно закрывается. Мы ожидали бы тот вызов Close() неявно сигнализировал бы о потоках ожидания.

Мы разыскали это как причину, которую не закрывали некоторые наши сервисы окон с такой скоростью, как мы хотели бы. Мы изменяем весь наш Dispose реализации то завершение ManualResetEvent ссылки на вызов Set сначала.

Может любой объяснять почему Close неявно не звонит Set? Когда Вы хотели бы, чтобы поток ожидания продолжил ожидать?

Вот наш тестовый код для демонстрации наших результатов:

    private static readonly Stopwatch _timer = Stopwatch.StartNew();

    public static void Test()
    {

        var sync = new ManualResetEvent(false);

        ThreadPool.QueueUserWorkItem(state =>
                                         {
                                             Log("ThreadPool enter, waiting 250ms...");
                                             sync.WaitOne(250);
                                             Log("ThreadPool exit");
                                         });

        Log("Main sleeping 100");
        Thread.Sleep(100);
        Log("Main about to close");
        // sync.Set();      // Is Set called implicitly?  No...
        sync.Close();

        Log("Main waiting for exit 500ms");
        Thread.Sleep(500);
    }

    private static void Log(string text)
    {
        Console.WriteLine("{0:0} {1}", _timer.ElapsedMilliseconds, text);  
    }

Когда мы выполняем этот код с Set звоните прокомментировал, мы получаем это..

0 Main sleeping 100
0 ThreadPool enter, waiting 250ms...
103 Main about to close
103 Main waiting for exit 500ms
259 ThreadPool exit

Когда мы явно звоним Set мы получаем это..

0 Main sleeping 100
0 ThreadPool enter, waiting 250ms...
98 Main about to close
98 ThreadPool exit
98 Main waiting for exit 500ms
6
задан Samuel Neff 6 April 2010 в 16:03
поделиться

2 ответа

Close - это средство удаления объекта ( Close и Dispose в этом классе yield идентичное поведение). На состояние ручки это не влияет. Предполагать, что во всех случаях пользователь захочет, чтобы поток ждал дескриптора, который я закрыл для продолжения, не представляется разумным. Фактически, тот факт, что дескриптор используется , должен указывать на то, что вы не должны в первую очередь вызывать Close .

Это не вопрос «почему не следует неявно вызывать Set ?», Это концептуальная проблема: если вы звоните Close , , вы не должны дольше заботиться об объекте . Используйте Set и Reset для управления потоком выполнения между потоками; не вызывайте Close (или Dispose ) для любого объекта, включая WaitHandle , пока они не перестанут использоваться.

3
ответ дан 17 December 2019 в 07:02
поделиться

Эти события синхронизации основаны на дескрипторах ожидания Win32, а метод Close () только освобождает их (например, Dispose () ) без сигнализации, и ожидающие потоки продолжают ждать.

1
ответ дан 17 December 2019 в 07:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: