Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there anything wrong with await Task.Run(() => semaphore.WaitOne())?

Title says it all. Is there anything wrong with await Task.Run(() => semaphore.WaitOne());? System.Threading.Semaphore isn't thread-affine, so I wouldn't think there would be a problem. I know that the SemaphoreSlim class is available, but I need to do cross-process synchronization, and SemaphoreSlim doesn't do that.

Or can/should I create my own custom type of WaitHandle?

like image 406
Zane Kaminski Avatar asked Apr 16 '14 19:04

Zane Kaminski


People also ask

Can a task run without semaphore?

Whenever a task wants access to the shared resource, it must acquire the semaphore first. The task should release the semaphore after it is done with the shared resource. Until this time all other tasks have to wait if they need access to shared resource as semaphore is not available.

Why you shouldn t use async void?

Async void methods can wreak havoc if the caller isn't expecting them to be async. When the return type is Task, the caller knows it's dealing with a future operation; when the return type is void, the caller might assume the method is complete by the time it returns.

Is task run asynchronous?

In . NET, Task. Run is used to asynchronously execute CPU-bound code.

Does task run use a new thread?

NET code does not mean there are separate new threads involved. Generally when using Task. Run() or similar constructs, a task runs on a separate thread (mostly a managed thread-pool one), managed by the . NET CLR.


1 Answers

If you're trying to keep the UI responsive while waiting for the semaphore here, it might make sense, but there's a catch: "Semaphores don't have owners". If you share the semaphore between two processes, and the other process crashes without calling Semaphore.Release(), the ownership over the shared resource will be lost. The remaining process may not be able to acquire it again.

IMO, the Mutex semantic would be more appropriate here, but with Mutex you'd need thread affinity. Perhaps, you can acquire the mutex, access the resource and release it on the same thread:

await Task.Factory.StartNew(() => 
{
    mutex.WaitOne();
    try
    {
        // use the shared resource
    }
    finally
    {
        mutex.ReleaseMutex(); 
    }
}, TaskCreationOptions.LongRunnning);

If that's not possible (e.g., because you need to access the shared resource on the main UI thread), you could use a dedicated thread for the mutex. This can be done with a custom task scheduler, e.g. Stephen Toub's StaTaskScheduler with numberOfThreads:1 (the helper thread doesn't have to be made STA in this case):

using (var scheduler = new StaTaskScheduler(numberOfThreads: 1))
{
    await Task.Factory.StartNew(
        () => mutex.WaitOne(), 
        CancellationToken.None,
        TaskCreationOptions.None,
        scheduler);
    try
    {
        // use the shared resource on the UI thread
    }
    finally
    {
        Task.Factory.StartNew(
            () => mutex.ReleaseMutex(), 
            CancellationToken.None,
            TaskCreationOptions.None,
            scheduler).Wait();
    }
}

Updated, if you're concerned about WinRT (i.e., .NET for Windows Store Apps) or Windows Phone, then Task.Factory.StartNew w/ TaskCreationOptions.LongRunning is still there, you can use it instead of new Thread() with StaTaskScheduler or something like my ThreadWithSerialSyncContext whenever you need a background thread with affinity.

like image 117
noseratio Avatar answered Sep 20 '22 04:09

noseratio