As Matthew points out on his blog, another potential solution to the concurrency issue is to stop further requests by disabling the button...
I have updated by DeadLock2.zip file to include a new fourth solution.
In this solution I have separated out the logic of the library functionality. I think I understand the intended model a little better now, and as I see it, it is responsible for echoing a stored message + some additional string. I have coded this into an "Echoer" class that internally stores the message.
Using this library, the UI requests an echo from the Echoer with the additional string "1 ". The result that is echoed is then used to update the Echoer's message property.
If you examine the solution I have uploaded, you will notice that there are no locks used. This implementation is thread safe due to the structuring of the program. Updates to the Echoer's Message property occur on the GUI thread. The worker thread is responsible for processing the echo and returning the new string. The thread safety is ensured by stopping the GUI thread from interacting with this variable until after the transaction is completed.
So why the differing views?
There are two perspectives on this issue. When I read the code originally I was viewing it from a concurrency mindset. Therefore you look for potential cases of concurrency and try to determine all of the potential race conditions. The fix to this issue is then to modify the library to include thread safety mechanisms. Thereby ensuring that the library will be usable in a concurrent environment.
We can also consider this from the perspective of an application developer using a non-thread safe library object. In this case the responsibility of ensuring thread safety lies in the UI, as the library cannot be changed.
And the motto of the story is?
Writing good concurrent programs is not hard... it is very hard. A slight oversight and you will have introduced unexpected bugs. These bugs are not the friendly kind that will appear in testing, these are the nasty kind that only show up on rare occasions (in my experience this is usually when it is critical that the don't show up).
One of the most important things to consider with any of these solutions is communication. How do you communicate that the line "button1.Enabled = false;" is absolutely critical to the safety of the application? If this line is removed, the safety of the application is compromised. In a team development environment you need to ensure that there is a good understanding of the strategies used to ensure that the application remains safe and live.
Patterns can help greatly with communication. I am really looking forward to seeing Matthew's future entries on this topic...
On Invoke and BeginInvoke
Basically I agree with Matthew, BeginInvoke is usually the better option. However, I would not go as far as saying that Invoke should never be used. Rather, it is my opinion that you should understand what you are trying to do and choose the one that is most appropriate. This in most cases will be BeginInvoke.
Friday, January 21, 2005
Concurrent Programming
Posted by Andrew Cain at 8:11 am
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment