Short version:
Use lock() to synchronize a Thread.Abort() call with critical sections.
Let me clarify the version:
Generally, when interrupting a stream, you will need to consider two types of code:
- Long code that doesn't suit you if it ends
- Code that must run its course
The first type is a type that we do not need if the user requested an interrupt. Maybe we were counting on a hundred billion, and he doesn’t care?
If we use sentinels such as the CancellationToken , are we unlikely to test them at each iteration of the non-essential code?
for(long i = 0; i < bajillion; i++){ if(cancellationToken.IsCancellationRequested) return false; counter++; }
So ugly. Therefore, for these cases, Thread.Abort() is a godsend.
Unfortunately, as some say, you cannot use Thread.Abort() because of the atomic code that absolutely needs to be run! The code has already deducted money from your account, now it must complete the transaction and transfer the money to the target account. Nobody likes money to disappear.
Fortunately, we have a mutual exception to help us with this. And C # does it pretty:
And in another place
lock(_lock)
The number of locks will always be <= number of sentries, because you will also need sentries for non-essential code (to speed up its execution). This makes the code a little prettier than the sentinel version, but it also makes the interrupt better because it does not need to wait for irrelevant things.
It should also be noted that a ThreadAbortException can be thrown anywhere, even in finally blocks. This unpredictability makes Thread.Abort() so inconsistent.
With locks, you avoid this by simply locking the entire try-catch-finally . This cleanup in finally is important, then the whole block can be locked. try blocks are usually executed as short as possible, one line is preferable, therefore we do not block unnecessary code.
This makes Thread.Abort() , as you say, a little less evil. You may not want to name it in the user interface thread, however, since you are now blocking it.