2

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?

  • 1
    Is there a race here? Is it possible that the data arrives after the unsubscribe, but before the subscribe? – Eric Lippert Jun 17 '16 at 17:29
  • @EricLippert I do not know the answer to that at the moment. But I am more overall just curious what happens (if the data did show up). – Snoop Jun 17 '16 at 17:32
4

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.

  • When you say "infinite loop", do you maybe mean some situation where the data keeps on coming asynchronously so it becomes impossible to leave the finally? – Snoop Jun 17 '16 at 17:37
  • @StevieV: No, I mean, suppose you have a third party library, you start a thread, the library has a method that goes into an infinite loop inside a finally, and you try to abort the thread. Does the thread actually abort? No. Finally blocks are special. If you have a third party library like that, find a better one. In your case, all the finally does is update a list of handlers. Remember, the handling doesn't run in the finally, updating the list of handlers runs in the finally in your code. – Eric Lippert Jun 17 '16 at 17:39
  • I didn't actually think "if I have an infinite loop inside a finally block doesn't that mean that the thread cannot be aborted?" when I read that. I thought "what if you're inside a finally block further up the call stack?" – Mason Wheeler Jun 17 '16 at 17:41
  • Why would anyone ever put an infinite loop in a finally block in the first place? That sounds like a monumentally bad idea. – Robert Harvey Jun 17 '16 at 17:42
  • 1
    @RobertHarvey: The issue I am alluding to is people sometimes have this crazy idea that they can put ill-behaved or possibly-hostile code in its own thread and then think that they have some sort of control over that thread by way of aborting it if something goes wrong. Bad idea. Hostile code that runs on a thread can pwn the thread quite thoroughly. You need to isolate buggy / hostile code to its own appdomain, or even better, process. – Eric Lippert Jun 17 '16 at 18:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.