Hohenheim
Hohenheim

Reputation: 175

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 ;)

Upvotes: 3

Views: 2298

Answers (2)

argaz
argaz

Reputation: 1488

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.

Upvotes: 4

Visual Vincent
Visual Vincent

Reputation: 18320

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.

Upvotes: 1

Related Questions