Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AutoResetEvent.WaitOne() cause deadlock

I'm writing a application with a critical region.

And I decide to use AutoResetEvent to achieve mutual exclusion. Here's the code

    public class MyViewModel
    {
        private AutoResetEvent lock = new AutoResetEvent(true);
        private aync Task CriticalRegion()
        {
            Dosomething();
        }


        public async Task Button_Click()
        {
            Debug.WriteLine("Entering Button_Click");
            lock.WaitOne();
            try
            {
                await CriticalRegion();
            }
            finally
            {
                lock.Set();
                Debug.WriteLine("Leaving Button_Click");

            }
        }

    }

I have a button whose click event calls the Button_Click() method

It works normally. But, if I'm quick enough to click the button for another time before the first call to Button_Click() completes, the whole app stops responding.

In the Debug window I find something like this

Entering Button_Click
Entering Button_Click

Looks like the method never completes.

I struggled a bit and find that if I change lock.WaitOne(); to

   if (!sync.WaitOne(TimeSpan.FromSeconds(1)))
   {
       return;
   }

In this case my app is able to avoid the deadlock,but I don't know why it works.

I only know about the IPC from my OS course and the async and await pattern in C#, and I'm not so familiar with the thread in .Net world.

I really want to understand what's really going on behind the scenes. Thanks for any replys ;)

like image 786
Hohenheim Avatar asked Sep 14 '26 07:09

Hohenheim


2 Answers

You have a deadlock because WaitOne is blocking the main thread (button click handler is executed on the main thread), while you haven't called ConfigureAwait(false) when calling await, which means that it tries to run the code which is after await on the main thread, even if it's blocked, which would causes a deadlock.

I suggest reading this post for a thorougher explanation of the dead lock situation.

For your code, I would suggest putting the lock deeper, probably within the async Task, and trying to use a more suitable pattern for locking, preferably, the lock statement, because using Event objects is awkward for mutual exclusion, as Hans stated in the comment.

like image 116
argaz Avatar answered Sep 15 '26 20:09

argaz


AutoResetEvent.WaitOne() will block infinitely until you call AutoResetEvent.Set(), which you never seem to do except for after the WaitOne() call.

Quoting the AutoResetEvent.WaitOne() documentation:

Blocks the current thread until the current WaitHandle receives a signal.

like image 44
Visual Vincent Avatar answered Sep 15 '26 21:09

Visual Vincent



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!