Why does my code cause a deadlock?

0

First I want to say that I'm sorry if this is a bad question. I had a question about this issue earlier this morning and could fix some issues, but I'm still getting a deadlock and I'm struggling with this the whole morning.

I'm trying to request chats from a server. In UWP, I need to do this asynchronously. My approach causes a deadlock at about every 5th try I'm running the following code.

The first await happens in OnNavigatedTo:

public async void OnNavigatedTo(NavigationParameters parameters)
{
    IsLoadMoreItemsPossible = true;
    if (_first)
    {
        _first = false;
        await LoadDataTaskAsync();
    }
}

Which calls LoadDataTaskAsync:

private async Task LoadDataTaskAsync()
{
    if (IsBusy)
    {
        return;
    }

    IsLoadMoreItemsPossible = false;
    IsBusy = true;
    IsFree = false;
    if (!CommonUtils.isInternetAvailable())
    {
        // load from local
    }
    await _remoteDataManager.requestChats();
}

_remoteDataManager.requestChats() gets the right method for the current platform:

public async Task requestChats()
{
    await _websocketManager.requestChats();
}

requestChats in my UWP WebsocketManager looks like this:

public async Task requestChats()
{
    dataWriter.WriteString(WebsocketRequestFactory.Create(SocketEventsEnm.GET_CHATS));
    await SendData(dataWriter);
}

And finally SendData, where the exception happens:

private async Task SendData(DataWriter dataWriter)
{
    try
    {
        _evaLogger.Info("Trying to send data...");
        await dataWriter.StoreAsync(); // This is where the exception occurs
        _evaLogger.Info("Data was sent");
    }
    catch (Exception e)
    {
        _evaLogger.Error(e.Message, e);
    }
}

_evaLogger writes into a logfile, which logs this when the deadlock happens:

12.12.2016 10:38:08 - Info: Websocket Opened

12.12.2016 10:38:08 - Info: Trying to send data...

12.12.2016 10:38:08 - Error: A method was called at an unexpected time. (Exception from HRESULT: 0x8000000E)

12.12.2016 10:38:09 - Info: Trying to send data...

12.12.2016 10:38:09 - Info: Data was sent

Sorry for the long question, I tried to only show the relevant code for the deadlock.

EDIT 1:

I tried Azhar Khorasany's suggestion in the comments to use semaphore while accessing the stream:

public class AsyncLock
{
    public readonly AsyncSemaphore m_semaphore;
    private readonly Task<Releaser> m_releaser;

    public AsyncLock()
    {
        m_semaphore = new AsyncSemaphore(1);
        m_releaser = Task.FromResult(new Releaser(this));
    }

    public Task<Releaser> LockAsync()
    {
        var wait = m_semaphore.WaitAsync();
        return wait.IsCompleted ?
            m_releaser :
            wait.ContinueWith((_, state) => new Releaser((AsyncLock)state),
                this, CancellationToken.None,
                TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
    }
}

New requestChats method:

private static readonly AsyncLock m_lock = new AsyncLock();

public async Task requestChats()
{
    using (await m_lock.LockAsync())
    {
        using (DataWriter dataWriter = new DataWriter(messageWebsocket.OutputStream))
        {
            _evaLogger.Info("dataWriter initialized requestChats.");
            dataWriter.WriteString(WebsocketRequestFactory.Create(SocketEventsEnm.GET_CHATS));
            await SendData(dataWriter, "requestChats");
        }
    }
    _evaLogger.Info("dataWriter disposed requestChats.");
}

Unfortunately, it didn't solve the deadlock issue:

13.12.2016 07:55:31 - Info: Websocket Opened

13.12.2016 07:55:32 - Info: dataWriter initialized requestChats.

13.12.2016 07:55:32 - Info: Trying to send data... requestChats

13.12.2016 07:55:32 - Error: A method was called at an unexpected time. (Exception from HRESULT: 0x8000000E)

13.12.2016 07:55:32 - Info: dataWriter disposed requestChats.

13.12.2016 07:55:32 - Info: Trying to send data... requestContacts

13.12.2016 07:55:32 - Info: dataWriter initialized requestContacts.

c#
asynchronous
deadlock
asked on Stack Overflow Dec 12, 2016 by Dennis Schröer • edited Dec 13, 2016 by Dennis Schröer

1 Answer

1

There are several potential problems in this code because it's clearly not written with parallel threads in mind. What your immediate problem is, as far as I can tell from your code, is that dataWriter shared among the threads. Imagine that one thread may be executing dataWriter.WriteString(...) while another thread is executing dataWriter.StoreAsync() and you see the problem. You need to read up about parallel programming and have a full understanding of how you code executes. Having flags like IsBusy may "work" in a one-thread-program it is bound to cause you headaches as soon as you have multiple threads.

Quick advice to your code: Remove your global declaradion of dataWriter and change the following code:

public async Task requestChats()
{
    /* declare dataWriter here so it becomes an instance variable*/
    dataWriter.WriteString(WebsocketRequestFactory.Create(SocketEventsEnm.GET_CHATS));
await SendData(dataWriter);
answered on Stack Overflow Dec 12, 2016 by K Ekegren • edited Dec 12, 2016 by K Ekegren

User contributions licensed under CC BY-SA 3.0