views:

213

answers:

1

I'm having some weird behavior in an application which is puzzling me.

I create a thread, let's call it worker, which is responsible for handling communication requests. Clients write on a pipe while the thread consumes the requests and send messages.

Now, the main loop of the thread has something like this:

lock(this)
{
  object_id = Transport.BeginSend(xxx, xxx, callback, yyy)
  clientsObjects[object_id] = client_id;
}

now the callback needs to access the client_id (its a bit more complicated than what I wrote, but the thing is that the callback receives the object_id, just assume BeginSend is a call to UdpClient.BeginSend

void Callback(IAsyncResult ar)
{
  State st = (State)ar;
  lock(this)
  {
    client_id = clientsObjects[st.object_id]
  }
}

Locks are there because the callback may fire so fast that it actually happens before clientsObjects[object_id] = client_id; can execute...

Ok, now.. the problem is it's not working, well it works now and then... why? If I trace the ManagedThreadIds of the threads which are executing the BeginSend and the one that is executing the callback I find that sometimes, they have the same ThreadId!!

Is that possible? How can that happen? Any suggestions about what am I doing wrong?

Comment: Actual code is not exactly like that, Transport is a wrapper around the UDPClient which allows changing the transport layer easily, locks aren't really locks but spinlocks ... but the concept itself is more or less what I've written down.

+1  A: 

Here is an older article that talks about the Stream.BeginRead() function actually operating synchronously, not asynchronously as you would expect. The article is from 2004, so I'm assuming it's referring to .NET 1.0/1.1. The article does not specifically refer to UdpClient.BeginSend(), but I've often wondered if the BeginXXX functions in the Socket stuff have the same behavior at times, especially if there is data to be read immediately. It might be worth checking the web to see if this is a possibility.

Is it possible to pass the client_id to the callback function via the state parameter of the BeginSend() function?

   object_id = Transport.BeginSend(xxx, xxx, Callback, client_id);
Matt Davis
Amazing, indeed sometimes the Asynchronous call becomes synchronous ... what a mess!!
Jorge Córdoba