Каково различие между Потоком. Сон (тайм-аут) и ManualResetEvent. Ожидать (тайм-аут)?

Оба Потока. Сон (тайм-аут) и resetEvent. Ожидайте (тайм-аут) выполнение причины для приостановки для, по крайней мере, timeout миллисекунды, так там различие между ними? Я знаю тот Поток. Сон заставляет поток бросать остаток от своего интервала времени, таким образом возможно приводящего ко сну, который длится намного дольше, чем попросивший относительно. Ожидание (тайм-аут) метод объекта ManualResetEvent имеют ту же проблему?

Править: Я знаю, что основной момент ManualResetEvent должен быть сообщен от другого потока - прямо сейчас я только обеспокоен случаем метода Ожидания события с тайм-аутом, указанным, и никакие другие вызывающие стороны, устанавливающие событие. Я хочу знать, более ли это надежно для пробуждения вовремя, чем Поток. Сон

13
задан Erik Forbes 8 June 2010 в 16:22
поделиться

6 ответов

Thread.Sleep (timeout) вызывает безусловное ожидание перед возобновлением выполнения. resetEvent.WaitOne (timeout) заставляет поток ждать, пока (1) событие не сработает, либо (2) не истечет время ожидания.

Смысл использования событий состоит в том, чтобы запускать их из другого потока, чтобы вы могли напрямую контролировать, когда поток просыпается. Если вам это не нужно, вы не должны использовать объекты событий.

РЕДАКТИРОВАТЬ: С точки зрения времени, они оба одинаково надежны. Однако ваш комментарий о «своевременном пробуждении» меня беспокоит. Зачем нужен код, чтобы вовремя просыпаться? Sleep и WaitOne на самом деле не рассчитаны на точность.

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

24
ответ дан 1 December 2019 в 17:51
поделиться

Как уже упоминалось, разница в том, что WaitOne может вернуться до времени ожидания, если будет получен сигнал. Сон гарантированно дождется времени сна.

Thread.Sleep в вызовах рефлектора:

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void SleepInternal(int millisecondsTimeout);

ManualResetEvent.Wait в вызовах рефлектора:

private static extern int WaitOneNative(SafeWaitHandle waitHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext);

Не уверен, есть ли разница между ними, но я посмотрю, смогу ли я что-нибудь найти.

2
ответ дан 1 December 2019 в 17:51
поделиться

Функция Sleep() уже давно не работает таким образом. Ее точность определяется периодом мультимедийного таймера, который можно изменить с помощью P/Invoking timeBeginPeriod(). К сожалению, на моей машине есть программа, которая устанавливает этот период равным одной миллисекунде, что делает сон точным до миллисекунды. Вот код, который вы можете попробовать сами:

using System;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;

class Program {
    static void Main(string[] args) {
        //timeBeginPeriod(1);
        var sw1 = Stopwatch.StartNew();
        for (int ix = 0; ix < 100; ++ix) Thread.Sleep(10);
        sw1.Stop();
        var sw2 = Stopwatch.StartNew();
        var mre = new ManualResetEvent(false);
        for (int ix = 0; ix < 100; ++ix) mre.WaitOne(10);
        sw1.Stop();
        Console.WriteLine("Sleep: {0}, Wait: {1}", sw1.ElapsedMilliseconds, sw2.ElapsedMilliseconds);
        Console.ReadLine();
        //timeEndPeriod(1);
    }
    [DllImport("winmm.dll")]
    private static extern int timeBeginPeriod(int period);
    [DllImport("winmm.dll")]
    private static extern int timeEndPeriod(int period);
}

Вывод на моей машине:

Sleep: 999, Wait: 1003

с вариативностью около 5 миллисекунд.

4
ответ дан 1 December 2019 в 17:51
поделиться

Для задержек и периодики я нашел Monitor.Wait хорошим выбором...

object timelock = new object();

lock (timelock) { Monitor.Wait(timelock, TimeSpan.FromMilliseconds(X.XX)); }

Это дает отличный результат....~1ms jitter или лучше, в зависимости от специфики приложения.

Как вы, возможно, уже знаете, Thread.Sleep(X) ненадежен и не может быть отменен.... Я избегаю его как чумы.

7
ответ дан 1 December 2019 в 17:51
поделиться

Спящий режим продолжается указанное время. Ожидание события может закончиться раньше, если о событии будет сообщено. Это цель событий: позволить одному потоку дать команду другому проснуться.

В одном потоке вы бы сказали:

    mre.WaitOne(10000); // ten seconds
    Console.WriteLine("Woke up!");

В другом вы бы сказали:

    mre.Set(); // this causes `WaitOne` to return in the first thread

Без вызова Set в другом потоке первый поток фактически спал бы в течение 10 секунд.

1
ответ дан 1 December 2019 в 17:51
поделиться

Основное различие между Thread.Sleep и ManualResetEvent.WaitOne заключается в том, что вы можете подать сигнал потоку, ожидающему ManualResetEvent, используя метод Set, что заставит поток проснуться раньше таймаута.

Если вы не подаете сигнал, то я ожидаю, что они будут вести себя очень похоже.

Из .NET Reflector я вижу, что метод ManualResetEvent.WaitOne в конечном итоге приводит к вызову внешнего метода со следующей сигнатурой:

int WaitOneNative(SafeWaitHandle waitHandle,
                  uint millisecondsTimeout,
                  bool hasThreadAffinity,
                  bool exitContext);

Тогда как Thread.Sleep вызывает этот внешний метод:

void SleepInternal(int millisecondsTimeout);

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

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

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