AutoResetEvent Reset immediately after Set

前端 未结 4 1114
花落未央
花落未央 2021-02-14 14:33

Consider the following pattern:

private AutoResetEvent signal = new AutoResetEvent(false);

private void Work()
{
    while (true)
    {
        Thread.Sleep(5000         


        
相关标签:
4条回答
  • 2021-02-14 15:13

    I would use TaskCompletionSources:

    private volatile TaskCompletionSource<int> signal = new TaskCompletionSource<int>();
    
    private void Work()
    {
        while (true)
        {
            Thread.Sleep(5000);
            var oldSignal = signal;
            signal = new TaskCompletionSource<int>()
            //has a waiting thread definitely been signaled by now?
            oldSignal.SetResult(0);
        }
    }
    
    public void WaitForNextEvent()
    {
        signal.Task.Wait();
    }
    

    By the time that the code calls SetResult, no new code entering WaitForNextEvent can obtain the TaskCompletionSource that is being signalled.

    0 讨论(0)
  • 2021-02-14 15:15

    There is no guarantee. This:

    AutoResetEvent flag = new AutoResetEvent(false);
    
    new Thread(() =>
    {
        Thread.CurrentThread.Priority = ThreadPriority.Lowest;
        Console.WriteLine("Work Item Started");
        flag.WaitOne();
        Console.WriteLine("Work Item Executed");
    }).Start();
    
    // For fast systems, you can help by occupying processors.
    for (int ix = 0; ix < 2; ++ix)
    {
        new Thread(() => { while (true) ; }).Start();
    }
    
    Thread.Sleep(1000);
    Console.WriteLine("Sleeped");
    
    flag.Set();
    // Decomment here to make it work
    //Thread.Sleep(1000);
    
    flag.Reset();
    Console.WriteLine("Finished");
    Console.ReadLine();
    

    won't print "Work Item Executed" on my system. If I add a Thread.Sleep between the Set and the Reset it prints it. Note that this is very processor dependent, so you could have to create tons of threads to "fill" the CPUs. On my PC it's reproducible 50% of the times :-)

    For the Exited:

    readonly object mylock = new object();
    

    then somewhere:

    lock (mylock)
    {
        // Your code goes here
    }
    

    and the WaitForExit:

    void WaitForExit()
    {
        lock (mylock) ;
        // exited
    }
    
    void bool IsExited()
    {
        bool lockTacken = false;
    
        try
        {
            Monitor.TryEnter(mylock, ref lockTacken);
        }
        finally
        {
            if (lockTacken)
            {
                Monitor.Exit(mylock);
            }
        }
    
        return lockTacken;
    }
    

    Note that the lock construct isn't compatible with async/await (as aren't nearly all the locking primitives of .NET)

    0 讨论(0)
  • 2021-02-14 15:17

    Instead of using AutoResetEvent or ManualResetEvent, use this:

    public sealed class Signaller
    {
        public void PulseAll()
        {
            lock (_lock)
            {
                Monitor.PulseAll(_lock);
            }
        }
    
        public void Pulse()
        {
            lock (_lock)
            {
                Monitor.Pulse(_lock);
            }
        }
    
        public void Wait()
        {
            Wait(Timeout.Infinite);
        }
    
        public bool Wait(int timeoutMilliseconds)
        {
            lock (_lock)
            {
                return Monitor.Wait(_lock, timeoutMilliseconds);
            }
        }
    
        private readonly object _lock = new object();
    }
    

    Then change your code like so:

    private Signaller signal = new Signaller();
    
    private void Work()
    {
        while (true)
        {
            Thread.Sleep(5000);
            signal.Pulse(); // Or signal.PulseAll() to signal ALL waiting threads.
        }
    }
    
    public void WaitForNextEvent()
    {
        signal.Wait();
    }
    
    0 讨论(0)
  • 2021-02-14 15:36

    I believe it is not guaranteed.

    However, your logic flow is not understood by me. If your main thread Sets the signal, why should it wait until that signal reaches its destination? Wouldn't it be better to continue your "after signal set" logic in that thread which was waiting?

    If you cannot do that, I recommend you to use second WaitHandle to signal the first thread that the second one has reveiced the signal. But I cannot see any pros of such a strategy.

    0 讨论(0)
提交回复
热议问题