0

From doc (EventWaitHandle.Set)

There is no guarantee that every call to the Set method will release a thread from an EventWaitHandle whose reset mode is EventResetMode.AutoReset. If two calls are too close together, so that the second call occurs before a thread has been released, only one thread is released. It is as if the second call did not happen. Also, if Set is called when there are no threads waiting and the EventWaitHandle is already signaled, the call has no effect.

Consider following code

private AutoResetEvent _are = new AutoResetEvent(false);

private void AnyMethod()
{
  await _are.Set();
}

Case 1

private async Task Method1(long timeout)
{  
  await _are.WaitOneAsync(timeout);
}

private async Task Method2()
{  
  await _are.WaitOneAsync();
}

private static Task WaitOneAsync(this WaitHandle waitHandle, long timeout)
{
    if (waitHandle == null)
        throw new ArgumentNullException("waitHandle");

    var tcs = new TaskCompletionSource<bool>();
    var rwh = ThreadPool.RegisterWaitForSingleObject(waitHandle,
        delegate { tcs.TrySetResult(true); }, null, timeout, true);
    var t = tcs.Task;
    t.ContinueWith( (antecedent) => rwh.Unregister(null));
    return t;
}

Case 2


private void Method1(int timeout)
{  
  _are.WaitOne(timeout);
}

private void Method2()
{  
  _are.WaitOne();
}

Imagine that both Method1 and Method2 are called and then AnyMethod releases one thread right in time when Method1 times out.

Is there guarantee about a thread releasement in the case 1 and 2 or Set method behavior applies generally to any thread releasement when either occurs close to another?

Yarl
  • 728
  • 1
  • 7
  • 26

1 Answers1

1

From doc...

The documentation quote describes what happens when Set is called and there are no threads waiting. The code in the rest of your question is all about calling Set when threads are waiting, so that paragraph of the docs doesn't apply.

Is there guarantee about thread releasement in case 1 and 2 or Set method behavior applies generally to any thread releasement when either occurs close to another?

Yes; one of the waiting threads will be released. If the event is Set before the timeout, it could be either thread; if the event is Set after the timeout, it will be the thread without the timeout.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • I guess you misunderstood. *There is no guarantee that every call to the Set method will release a thread from an EventWaitHandle whose reset mode is EventResetMode.AutoReset. If two calls are too close together, so that the second call occurs before a thread has been released, only one thread is released.* Question: Waiting thread just times out, `Set` method is called very close to timeout. Is it possible that `Set` method will fail or it is guaranteed that if wait timeouts, `Set` will succeed against the other thread? I am perhaps lazy to go through responsible framework code to be honest. – Yarl Jan 23 '21 at 18:36
  • `Set` will always succeed, with one thread or the other. A wait with a timeout will not negate a `Set`. – Stephen Cleary Jan 23 '21 at 23:17
  • How it is possible? Why `Set` close to `Set` release just one thread and `Set` close to *timeout* will release some not timed out thread? – Yarl Jan 24 '21 at 10:30
  • @Ucho: `Set` close to `Set` does release a thread, but there's no "counter" of any kind. Events are either set or unset, so setting one that is already set is a noop. Regarding the wait timeouts, if the `Set` is called before the timeout, then one thread will be released; if the `Set` is called after the timeout, then one thread will be released. At the time the `Set` happens, either the timeout has occurred or it has not. – Stephen Cleary Jan 24 '21 at 14:18
  • I know these. I just wonder why if 2 close `Set`calls can release just 1 thread, why the same cannot happen with `WaitOne` timeout and `Set` if they are close, i.e. *timeout* then `Set`. It seems `Set` uses *internal static extern bool SetEvent(SafeWaitHandle handle);* while `WaitOne`uses *private static extern int SignalAndWaitNative(IntPtr waitHandleToSignal, IntPtr waitHandleToWaitOn, int millisecondsTimeout);*. – Yarl Jan 24 '21 at 16:12
  • If the timeout occurs before the `Set`, then there will only be one thread waiting at the time the `Set` takes effect (the thread without the timeout), and that thread will be released. – Stephen Cleary Jan 24 '21 at 17:46
  • Can you prove that? – Yarl Jan 30 '21 at 21:33
  • 1
    @Ucho: That's how an event works. If there's a thread waiting when `Set` is called, then it is released. – Stephen Cleary Feb 01 '21 at 01:00