Pregunta

Background

My program communicates with a device that is usually asynchronous, but can sometimes behave synchronously. I have an event handler that I use for receiving the data asynchronously, then I have a separate event handler that I use when the device is in the synchronous mode. So, when I need to communicate with the device synchronously I will unsubscribe from the asynchronous handler, and subscribe to the synchronous handler as follows:

try
{
    // temporarily receive data synchronously
    this.myDevice.DataReceived 
        -= this.AsynchronousHandler;
    this.myDevice.DataReceived 
        += new SerialDataReceivedEventHandler(this.SynchronousHandler);

    // do the communication...
}
finally
{
    // go back to receiving asynchronously
    this.myDevice.DataReceived 
        -= this.SynchronousHandler;
    this.myDevice.DataReceived 
        += new SerialDataReceivedEventHandler(this.AsynchronousHandler);
}

Now, what I am anticipating is that there could be some kind of a problem with subscription/un-subscribing in the finally clause. Now, I realize that this will be highly unlikely, because the subscription process is the very last statement of the finally clause... However, let's say that I receive some data while the finally clause is still being executed and that the event-handler gets called.

Question

Will the event get handled properly even though it was handled while a finally clause is still being executed? Or, does it not matter at all?

¿Fue útil?

Solución

It shouldn't matter. finally blocks are special, but they are not special in a way that matters to your program.

Finally blocks are special because, for example, the runtime will delay a thread abort exception until after control leaves a finally block. (And if you are now thinking "if I have an infinite loop inside a finally block doesn't that mean that the thread cannot be aborted?" then you are thinking correctly. This is just one of many reasons why trying to abort a thread is a bad idea.)

But from the perspective of your control flow, you can think of a finally as simply yet another block of code that runs when the try block is done. (Regardless of whether the try block is done normally or exceptionally.)

My concern here is not the finally, but rather all the possible races. There is a moment in time where the unsubscribe has happened, and the subscribe has not. Could an event be triggered in that moment and then lost, since there is no subscriber? In a single threaded program, plainly not, but suppose the event source is running on another thread? There's a short gap in there where there are no listeners.

Licenciado bajo: CC-BY-SA con atribución
scroll top