等待Task.Run(()=> semaphore.WaitOne())有什么问题吗?

Zan*_*ski 7 .net c# multithreading thread-safety task-parallel-library

标题说明了一切.有什么不对await Task.Run(() => semaphore.WaitOne());吗?System.Threading.Semaphore不是线程仿射,所以我不认为会有问题.我知道这个SemaphoreSlim类是可用的,但是我需要进行跨进程同步,而SemaphoreSlim不是那样做.

或者我可以/应该创建自己的自定义类型WaitHandle吗?

nos*_*tio 6

如果您试图在等待信号灯时使UI保持响应,这可能是有道理的,但是有一个陷阱:“信号灯没有所有者”。如果您在两个进程之间共享信号量,而另一个进程崩溃而没有调用Semaphore.Release()则对共享资源的所有权将丢失。剩余的过程可能无法再次获取它。

IMO,这里的Mutex语义会更合适,但是Mutex您需要线程关联。也许,您可以获取互斥体,访问资源并在同一线程上释放它:

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

如果那是不可能的(例如,因为您需要访问主UI线程上的共享资源),则可以将专用线程用于互斥量。这可以使用自定义任务调度程序来完成,例如Stephen Toub的StaTaskSchedulerwith numberOfThreads:1(在这种情况下,不必使STA成为辅助线程):

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

更新后,如果您担心WinRT(即Windows Store Apps的.NET)或Windows Phone,则Task.Factory.StartNeww / TaskCreationOptions.LongRunning仍然存在,只要需要有亲和力的后台线程,就可以使用它代替new Thread()with StaTaskScheduler或与之类似的东西ThreadWithSerialSyncContext