1

I have the following 3 simplified methods for a client (Windows Phone 8) - server C# app I'm working on:

 private object sockLock = 1;
 private System.Threading.Timer _timer = new Timer(onTimer);

 void _sock_MessageReceived( ... )
 {
     lock(sockLock)
     {
         if( something )  //the server received the packet, so i can stop the timer
            _timer.Change(Timeout.Infinite, Timeout.Infinite);
     }
 }

 void onTimer( ... )
 {
    bool sendRequst = false;
    lock(sockLock)
    {
        if ( conditions from critical section )
           sendRequest = true;
    }
    if(sendRequest)
         SendRequest( ... ); //replay the packet
 }

 async void SendRequest(Request req)  //also called from GUI or user input
 {
        byte[] data = req.ToByteArray();
        if (data.Length == 0)
            return;

        bool lockTaken = false;
        Monitor.Enter(sockLock, ref lockTaken);
        if(!lockTaken)
        {
            Debug.WriteLine("Monitor.Enter failed !!!");
            return;
        }
        try
        {
            DataWriter dw = await GetSockStreamAsync();   //doesn't use lock in any way, it's just a lazy init

            lastReq = req;
            dw.WriteBytes(data);
            await dw.StoreAsync();

            await dw.FlushAsync();
            _timer.Change(10, Timeout.Infinite);
        }
        finally
        {
            Monitor.Exit(sockLock);  //here it throws exception
        }
 }

Long story short: I'm sending some UDP packets to a server, and the server also responds with the last SEQ value it received. After sending a packet I start a timer, and if the server doesn't respond in time, I replay that packet.

In all of the methods except the SendRequest method I can use lock, so there's no way of forgetting to release sockLock.

In SendRequest however, I need to 'await', and thus I'm unable to use lock for some reason I didn't give much thought, so the solution to synchronize is to use Monitor.

Now when the SendRequest is called from the GUI, it works, but when it's called from the onTimer function, it throws an SynchronizationLockException at Monitor.Exit(sockLock).

     Object synchronization method was called from an unsynchronized block of code.
   at System.Threading.Monitor.Exit(Object obj)
   at AbsMouse.AbsMouseClient.<SendRequestAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__1(Object state)
   at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()}

Are there any hidden side effects caused by 'await', or any other things that I'm missing in regards to this problem ?

Thanks in advance !

warwolf
  • 65
  • 7

0 Answers0