c# lock and listen to CancellationToken - c#

I want to use lock or a similar synchronization to protect a critical section. At the same time I want to listen to a CancellationToken.
Right now I'm using a mutex like this, but mutex doesn't have as good performance. Can I use any of other synchronization classes (including the new .Net 4.0) instead of the mutex?
WaitHandle.WaitAny(new[] { CancelToken.WaitHandle, _mutex});
CancelToken.ThrowIfCancellationRequested();

Take a look at the new .NET 4.0 Framework feature SemaphoreSlim Class. It provides SemaphoreSlim.Wait(CancellationToken) method.
Blocks the current thread until it can enter the SemaphoreSlim, while
observing a CancellationToken
From some point of view using Semaphore in such simple case could be an overhead because initially it was designed to provide an access for multiple threads, but perhaps you might find it useful.
EDIT: The code snippet
CancellationToken token = new CancellationToken();
SemaphoreSlim semaphore = new SemaphoreSlim(1,1);
bool tokenCanceled = false;
try {
try {
// block section entrance for other threads
semaphore.Wait(token);
}
catch (OperationCanceledException) {
// The token was canceled and the semaphore was NOT entered...
tokenCanceled = true;
}
// critical section code
// ...
if (token.IsCancellationRequested)
{
// ...
}
}
finally {
if (!tokenCanceled)
semaphore.Release();
}

private object _lockObject = new object();
lock (_lockObject)
{
// critical section
using (token.Register(() => token.ThrowIfCancellationRequested())
{
// Do something that might need cancelling.
}
}
Calling Cancel() on a token will result in the ThrowIfCancellationRequested() being invoked as that was what is hooked up to the Register callback. You can put whatever cancellation logic you want in here. This approach is great because you can cancel blocking calls by forcing the conditions that will cause the call to complete.
ThrowIfCancellationRequested throws a OperationCanceledException. You need to handle this on the calling thread or your whole process could be brought down. A simple way of doing this is by starting your task using the Task class which will aggregate all the exceptions up for you to handle on the calling thread.
try
{
var t = new Task(() => LongRunningMethod());
t.Start();
t.Wait();
}
catch (AggregateException ex)
{
ex.Handle(x => true); // this effectively swallows any exceptions
}
Some good stuff here covering co-operative cancellation

You can use Monitor.TryEnter with timeout to wait for the lock and check periodically for cancellation.
private bool TryEnterSyncLock(object syncObject)
{
while(!Monitor.TryEnter(syncObject, TimeSpan.FromMilliseconds(100)))
{
if (cts_.IsCancellationRequested)
return false;
}
return true;
}
Note that I would not recommend this in high contention situations as it can impact performance. I would use it as a safety mechanism against deadlocks in case you cannot use SemaphoreSlim as it has different same thread re-entrancy semantics than Monitor.Enter.
After returning true, lock on syncObject has to be released using Monitor.Exit.

Related

Method should throw an exception when called by another thread before completion

I have a method StartProcess(). I want this method to throw an exception if the same method is called by another thread at the same time or by the same initial thread before EndProcess() is called.
I tried the Monitor class but I wasn't sure how to apply it to the above stated case. What I saw that was close to what I was looking for was:
var obj = new Object();
// Define the critical section.
Monitor.Enter(obj);
try {
// Code to execute one thread at a time.
}
// catch blocks go here.
finally {
Monitor.Exit(obj);
}
I need guidance to handle my exact stated scenario. I've been trying all day but couldn't get it to work.
You need a synchronization mechanism that disallows reentrancy, and the Monitor is not one of them (it is reentrant by design). My suggestion is to use a SemaphoreSlim, which is not reentrant. This mechanism doesn't look to see which thread is calling it. It's just a simple counter. In order to acquire the semaphore if it's available, or return instantly if it's not available, you can invoke the Wait method with a zero millisecondsTimeout, like this:
SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
bool acquired = semaphore.Wait(0);
if (!acquired) throw new InvalidOperationException();
try
{
// Code to execute disallowing concurrency
}
finally
{
semaphore.Release();
}
It seems you are looking for the ManualResetEventSlim:
ManualResetEventSlim resetEvent = new ManualResetEventSlim();
// Block other calls.
resetEvent.Wait();
// Reset state to block next calls.
resetEvent.Reset();
try
{
// Your code
}
finally
{
// Set state to allow next call to proceed.
resetEvent.Set();
}

Managing task cancellation and completion on a concurrent thread

[ This question needs to be reimagined. One of my thread queues MUST run on an STA thread, and the code below does not accommodate that. In particular it seems Task<> chooses its own thread and that just is not going to work for me. ]
I have a task queue (BlockingCollection) that I'm running through on a dedicated thread. That queue receives a series of Task<> objects that it runs sequentially within that thread via a while loop.
I need a means of Cancelling that series of tasks, and a means of knowing that the tasks are all complete. I have not been able to figure out how to do this.
Here's a fragment of my queuing class. ProcessQueue is run on a separate thread from main. QueueJob calls occur on the main thread.
using Job = Tuple<Task<bool>, string>;
public class JobProcessor
{
private readonly BlockingCollection<Job> m_queue = new BlockingCollection<Job>();
volatile bool cancel_queue = false;
private bool ProcessQueue()
{
while (true)
{
if (m_queue.IsAddingCompleted)
break;
Job tuple;
if (!m_queue.TryTake(out tuple, Timeout.Infinite))
break;
var task = tuple.Item1;
var taskName = tuple.Item2;
try
{
Console.WriteLine("Task {0}::{1} starting", this.name, taskName);
task.RunSynchronously();
Console.WriteLine("Task {0}::{1} completed", this.name, taskName);
}
catch (Exception e)
{
string message = e.Message;
}
if (cancel_queue) // CANCEL BY ERASING TASKS AND NOT RUNNING.
{
while (m_queue.TryTake(out tuple))
{
}
}
} // while(true)
return true;
}
public Task<bool> QueueJob(Func<bool> input)
{
var task = new Task<bool>(input);
try
{
m_queue.Add(Tuple.Create(task, input.Method.Name));
}
catch (InvalidOperationException)
{
Task<bool> dummy = new Task<bool>(() => false);
dummy.Start();
return dummy;
}
return task;
}
Here are the functions that trouble me:
public void ClearQueue()
{
cancel_queue = true;
// wait for queue to become empty. HOW?
cancel_queue = false;
}
public void WaitForCompletion()
{
// wait for all tasks to be completed.
// not sufficient to wait for empty queue because the last task
// must also execute and finish. HOW?
}
}
Here is some usage:
class SomeClass
{
void Test()
{
JobProcessor jp = new JobProcessor();
// launch Processor loop on separate thread... code not shown.
// send a bunch of jobs via QueueJob... code not show.
// launch dialog... code not shown.
if (dialog_result == Result.Cancel)
jp.ClearQueue();
if (dialog_result == Result.Proceed)
jp.WaitForCompletion();
}
}
The idea is after the work is completed or cancelled, new work may be posted. In general though, new work may come in asynchronously. WaitForCompletion might in fact be "when all work is done, inform the user and then do other stuff", so it doesn't strictly have to be a synchronous function call like above, but I can't figure how to make these happen.
(One further complication, I expect to have several queues that interact. While I am careful to keep things parallelized in a way to prevent deadlocks, I am not confident what happens when cancellation is introduced into the mix, but this is probably beyond scope for this question.)
WaitForCompletion() sounds easy enough. Create a semaphore or event, create a task whose only action is to signal the semaphore, queue up the task, wait on the semaphore.
When the thread finishes the last 'real' task, the semaphore task will be run and so the thread that called WaitForCompletion will become ready/running:)
Would not a similar approach work for cancellation? Have a very high priority thread that you create/signal that drains the queue of all pending jobs, disposing them, queueing up the semaphore task and waiting for the 'last task done' signal?

How to cancel a task on Thread.Abort()

I'm implementing a Method called by someone else. If my Method takes to long the caller will call Thread.Abort(). I start some tasks in my Method, and need to cancel those if my thread get aborted.
I currently guess the timeout I have and cancel the tasks after this timespan. It is not always the same timeout, depending on the operations executed before my method.
Are there a way to tie my tasks to that thread lifetime?
Update
To prevent any further comments, that I should not use Thread.Abort(), this is the code that handles the abort (not called by me, can't change that):
using (var cancelationTokenSource = new CancellationTokenSource())
{
try
{
DoWork(cancelationTokenSource.Token);
}
catch (ThreadAbortException)
{
cancelationTokenSource.Cancel();
throw;
}
}
I use the CancellationToken not Thread.Abort()
You can handle ThreadAbortException to deal with cleanup, including aborting other threads if ncessary.
void MyThreadProc()
{
try
{
//Do interesting things
}
catch ( ThreadAbortException e )
{
childThread.Abort();
}
}

SemaphoreSlim.WaitAsync before/after try block

I know that in the sync world the first snippet is right, but what's about WaitAsync and async/await magic? Please give me some .net internals.
await _semaphore.WaitAsync();
try
{
// todo
}
finally
{
_semaphore.Release();
}
or
try
{
await _semaphore.WaitAsync();
// todo
}
finally
{
_semaphore.Release();
}
According to MSDN, SemaphoreSlim.WaitAsync may throw:
ObjectDisposedException - If the semaphore has been disposed
ArgumentOutOfRangeException - if you choose the overload which accepts an int and it is a negative number (excluding -1)
In both cases, the SemaphoreSlim wont acquire the lock, which makes it unnessacery to release it in a finally block.
One thing to note is if the object is disposed or null in the second example, the finally block will execute and either trigger another exception or call Release which might have not acquired any locks to release in the first place.
To conclude, I would go with the former for consistency with non-async locks and avoiding exceptions in the finally block
Both options are dangerous if we think about ThreadAbortException.
Consider Option 1 and ThreadAbortException happening between WaitAsync and try. In this case a semaphore lock would be acquired but never released. Eventually that would lead to a deadlock.
await _semaphore.WaitAsync();
// ThreadAbortException happens here
try
{
// todo
}
finally
{
_semaphore.Release();
}
Now in Option 2, if ThreadAbortException happens before a lock has been acquired, we'd still try to release somebody else's lock, or we'd get SemaphoreFullException if the semaphore is not locked.
try
{
// ThreadAbortException happens here
await _semaphore.WaitAsync();
// todo
}
finally
{
_semaphore.Release();
}
Theoretically, we can go with Option 2 and track whether a lock was actually acquired. For that we're going to put lock acquisition and tracking logic into another (inner) try-finally statement in a finally block. The reason is that ThreadAbortException doesn't interrupt finally block execution. So we'll have something like this:
var isTaken = false;
try
{
try
{
}
finally
{
await _semaphore.WaitAsync();
isTaken = true;
}
// todo
}
finally
{
if (isTaken)
{
_semaphore.Release();
}
}
Unfortunately, we're still not safe. The problem is that Thread.Abort locks the calling thread until the aborting thread leaves a protected region (the inner finally block in our scenario). That can lead to a deadlock. To avoid infinite or long-running semaphore awaiting we can interrupt it periodically and give ThreadAbortException a chance to interrupt execution. Now the logic feels safe.
var isTaken = false;
try
{
do
{
try
{
}
finally
{
isTaken = await _semaphore.WaitAsync(TimeSpan.FromSeconds(1));
}
}
while(!isTaken);
// todo
}
finally
{
if (isTaken)
{
_semaphore.Release();
}
}
If there's an exception inside WaitAsync the semaphore was not acquired, so a Release is unnecessary and should be avoided. You should go with the first snippet.
If you're worried about exceptions in the actual acquiring of the semaphore (which aren't likely, other than NullReferenceException) you could try-catch it independently:
try
{
await _semaphore.WaitAsync();
}
catch
{
// handle
}
try
{
// todo
}
finally
{
_semaphore.Release();
}
Your first option is preferred to avoid calling release in the event that the Wait call threw. Though, with c#8.0 we can write things so that we don't have so much ugly nesting on each our methods requiring the use of a semaphore.
Usage:
public async Task YourMethod()
{
using await _semaphore.LockAsync();
// todo
} //the using statement will auto-release the semaphore
Here's the extension method:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace YourNamespace
{
public static class SemaphorSlimExtensions
{
public static IDisposable LockSync(this SemaphoreSlim semaphore)
{
if (semaphore == null)
throw new ArgumentNullException(nameof(semaphore));
var wrapper = new AutoReleaseSemaphoreWrapper(semaphore);
semaphore.Wait();
return wrapper;
}
public static async Task<IDisposable> LockAsync(this SemaphoreSlim semaphore)
{
if (semaphore == null)
throw new ArgumentNullException(nameof(semaphore));
var wrapper = new AutoReleaseSemaphoreWrapper(semaphore);
await semaphore.WaitAsync();
return wrapper;
}
}
}
And the IDisposable wrapper:
using System;
using System.Threading;
namespace YourNamespace
{
public class AutoReleaseSemaphoreWrapper : IDisposable
{
private readonly SemaphoreSlim _semaphore;
public AutoReleaseSemaphoreWrapper(SemaphoreSlim semaphore )
{
_semaphore = semaphore;
}
public void Dispose()
{
try
{
_semaphore.Release();
}
catch { }
}
}
}
This is an attempted improvement of Bill Tarbell's LockSync extension method for the SemaphoreSlim class. By using a value-type IDisposable wrapper and a ValueTask return type, it is possible to reduce significantly the additional allocations beyond what the SemaphoreSlim class allocates by itself.
public static ReleaseToken Lock(this SemaphoreSlim semaphore,
CancellationToken cancellationToken = default)
{
semaphore.Wait(cancellationToken);
return new ReleaseToken(semaphore);
}
public static async ValueTask<ReleaseToken> LockAsync(this SemaphoreSlim semaphore,
CancellationToken cancellationToken = default)
{
await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
return new ReleaseToken(semaphore);
}
public readonly struct ReleaseToken : IDisposable
{
private readonly SemaphoreSlim _semaphore;
public ReleaseToken(SemaphoreSlim semaphore) => _semaphore = semaphore;
public void Dispose() => _semaphore?.Release();
}
Usage example (sync/async):
using (semaphore.Lock())
{
DoStuff();
}
using (await semaphore.LockAsync())
{
await DoStuffAsync();
}
The synchronous Lock is always allocation-free, regardless of whether the semaphore is acquired immediately or after a blocking wait. The asynchronous LockAsync is also allocation-free, but only when the semaphore is acquired synchronously (when it's CurrentCount happens to be positive at the time). When there is contention and the LockAsync must complete asynchronously, 144 bytes are allocated additionally to the standard SemaphoreSlim.WaitAsync allocations (which are 88 bytes without CancellationToken, and 497 bytes with cancelable CancellationToken as of .NET 5 on a 64 bit machine).
From the docs:
The use of the ValueTask<TResult> type is supported starting with C# 7.0, and is not supported by any version of Visual Basic.
readonly structs are available beginning with C# 7.2.
Also here is explained why the IDisposable ReleaseToken struct is not boxed by the using statement.
This is a mix of an answer and a question.
From an article about lock(){} implementation:
The problem here is that if the compiler generates a no-op instruction between the monitor enter and the try-protected region then it is possible for the runtime to throw a thread abort exception after the monitor enter but before the try. In that scenario, the finally never runs so the lock leaks, probably eventually deadlocking the program. It would be nice if this were impossible in unoptimized and optimized builds.
(https://blogs.msdn.microsoft.com/ericlippert/2009/03/06/locks-and-exceptions-do-not-mix/)
Of course, lock is not the same, but from this note we could conclude, that it might also be better to put the SemaphoreSlim.WaitAsync() inside the try block, if it also offered a way to determine if the lock was acquired successfully (as Monitor.Enter as described in the article does). However, SemaphoreSlim does not offer such a mechanism.
This article about the implementation of using says:
using (Font font1 = new Font("Arial", 10.0f))
{
byte charset = font1.GdiCharSet;
}
is transformed to:
{
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}
If a noop can be generated between a Monitor.Enter() and its immediately following try, wouldn't the same problem apply to the transformed using code, either?
Maybe this implementation of AsyncSemaphore
https://github.com/Microsoft/vs-threading/blob/81db9bbc559e641c2b2baf2b811d959f0c0adf24/src/Microsoft.VisualStudio.Threading/AsyncSemaphore.cs
and extensions for SemaphoreSlim
https://github.com/StephenCleary/AsyncEx/blob/02341dbaf3df62e97c4bbaeb6d6606d345f9cda5/src/Nito.AsyncEx.Coordination/SemaphoreSlimExtensions.cs
are also interesting.

Classic never-ending thread loop using tasks?

Given is a very common threading scenario:
Declaration
private Thread _thread;
private bool _isRunning = false;
Start
_thread = new Thread(() => NeverEndingProc());
thread.Start();
Method
private void NeverEndingProc() {
while(_isRunning) {
do();
}
}
Possibly used in a asynchronous tcp listener that awaits callbacks until it gets stopped by letting the thread run out (_isRunning = false).
Now I'm wondering: Is it possible to do the same thing with Task? Using a CancellationToken? Or are Tasks only for procedures that are expected to end and report status?
You can certainly do this just by passing NeverEndingProc to Task.Run.
However, there is one important difference in functionality: if an exception is propagated out of NeverEndingProc in a bare Thread, it will crash the process. If it is in a Task, it will raise TaskScheduler.UnobservedException and then be silently ignored (as of .NET 4.5).
That said, there are alternatives you can explore. Reactive Extensions, for example, pretty much removes any need for the "infinite thread loop".
One reason to use Task + CancellationToken is to make the individual processes and their cancellation more independent of each other. In your example, notice how NeverEndingProc needs a direct reference to the _isRunning field in the same class. Instead, you could accept an external token:
Start:
public void StartNeverEndingProc(CancellationToken token) {
Task.Factory.StartNew(() => NeverEndingProc(token), token);
}
Method:
private void NeverEndingProc(CancellationToken token) {
while (true) {
token.ThrowIfCancellationRequested();
do();
}
}
Now cancellation is managed by the caller, and can be applied to multiple independent tasks:
var instance = new YourClass();
var cts = new CancellationTokenSource();
instance.StartNeverEndingProc(cts.Token); // start your task
StartOtherProc(cts.Token); // start another task
cts.Cancel(); // cancel both

Categories

Resources