First, Last, Contains etc… can be extremely dangerous (yet extremely useful :))

Most of the operators in the set of Observable extension methods are operators that return an IObservable. Some of the operators however return something else, such as First, Last, Contains etc…

These operations are blocking operations, they block the current thread to wait for a specific set of messages to come in on the IObservable they operate on. This is a great way to escape out of the IObservable e.g. you do want to block your program until a specific message comes in.

Power comes with great responsibility

Of course like everywhere else, this power of escaping out of the IObservable comes with great responsibility: You need to be careful which thread is responsible for sending messages to the IObservable.

Imagine that you have created an Observable using FromEvent to listen to button clicks on the UI. At some point you decide to run some code that needs to wait in the middle till the button is clicked, so you call .First() on the Observable. If this code happened to run on the UI thread, you have now created a deadlock!!!

What happened?

As you were using Rx in a UI context, you have set the SynchronizationContext as such (default in Silverlight). This means that all messages from Rx come back on the UI Thread by default by posting these messages into the message loop queue. The message loop is processes the queue on the UI thread if no other code is executing there, however we called First() on the UI thread which is a blocking operation, meaning it won’t yield control of the UI thread until it returns a value. Now that the UI thread will no longer process messages until First is done, no Rx messages can come in. First and Rx messages are blocked on each other, and thus we are in a deadlock!!!

How do I avoid this?

Most of the times it is best to avoid blocking operations and to subscribe to the IObservable instead. If you need to have advanced control over the Observable, e.g. you need to wait for multiple Observables to produce values, use one of the many binary operators such as Merge, Zip, CombineLatest etc…
If you’re really only interested in the first value, use .Take(1) and subscribe to that.

If you really need the blocking behavior, make sure you know which thread you’re running on.

For Language Geeks

If you get dizzy hearing the word Monad alone, you can stop reading here 🙂 If you’re interested in a little bit more theory, read on…

As discussed in Brian and Erik’s expert to export talk on Rx, IObservable is a monad. One of the things with monads is that operations are considered safe as long as you stay in the monad. Once you leave the monad all bets are off. That is exactly what is happening with these operators. They take something that is inside the monad and try to exit the monad. These operators are to the IObservable monad as UnsafePerformIO is to the IO monad.

Comments (0)

Skip to main content