【问题标题】:Waiting on a named semaphore with WaitOne(100) vs WaitOne(0) + Task.Delay(100)使用 WaitOne(100) 与 WaitOne(0) + Task.Delay(100) 等待命名信号量
【发布时间】:2014-10-12 12:06:21
【问题描述】:

我需要访问由两个进程共享的 Windows 8.1 应用程序中的资源:应用程序本身和后台任务,所以我需要一个名为 SemaphoreSemaphoreSlim 不适用于那里,因为我在之间进行异步工作获取和释放我不能使用Mutex

我在 PCL 中创建了一个类,该类创建信号量并允许我以这种方式等待 WaitOne 方法:

public sealed class AsyncSemaphore:IDisposable
{
    Semaphore _semaphore;
    public AsyncSemaphore(int initialCount, int maximumCount, string name)
    {
        _semaphore = new Semaphore(initialCount, maximumCount, name);
    }

    public IAsyncOperation<bool> WaitOneAsync()
    {
        return AsyncInfo.Run<bool>(cancellationToken => 
            Task.Run(()=>{
                while (!_semaphore.WaitOne(100))
                {
                    Logger.Log("Waiting...");
                    cancellationToken.ThrowIfCancellationRequested();
                }
                return true;
            },cancellationToken));
    }

    public int Release()
    {
        return _semaphore.Release();
    }

    public void Dispose()
    {
        if (_semaphore != null)
        {
            _semaphore.Dispose();
            _semaphore = null;
        }
    }
}

但是WaitOneAsync也可以这样写:

public IAsyncOperation<bool> WaitOneAsync()
{
    return AsyncInfo.Run<bool>(async cancellationToken =>
        {
            while (!_semaphore.WaitOne(0))
            {
                Logger.Log("Waiting...");
                await Task.Delay(100, cancellationToken);
            }
            return true;
        });
}

然后我在我的代码中这样使用它:

_semaphore= new AsyncSemaphore(1,1,"uniquename");

//....

await _semaphore.WaitOneAsync();
try
{
   //do more async work
}
finally
{
   _semaphore.Release();
}

这是正确的吗?哪一个最好并且使用更少的资源?

【问题讨论】:

  • 如果不是 SemaphoreSlim,_semaphore 是什么类型?
  • 它是一个 System.Threading.Semaphore,所以我可以使用命名信号量。 SemaphoreSlim 不允许使用命名的,因此它不会在两个不同的进程之间锁定,我添加了一些代码来澄清......
  • 不,这不正确。 WaitOne(100) 不像您的替代品那样具有 100 毫秒的最坏情况行为。
  • @Hans 很好的发现!当我写第二个选项时,我没有注意到这一点。谢谢。
  • @jmservera:在完整的桌面框架上,您可以使用ThreadPool.RegisterWaitForSingleObject。但是,在 Win8 上,您确实需要阻止线程池线程或轮询。在这两个中,我会选择阻塞线程池线程。

标签: c# async-await semaphore c#-5.0 winrt-async


【解决方案1】:

第一个选项在整个等待过程中保持一个线程,首先是同步等待,然后是忙等待(while 循环)。 第二个选项至少有点异步,因为它使用Task.Delay 等待,然后才诉诸忙等待。

第二个(异步)选项使用较少的资源,但需要等待整个超时(100ms)才能再次检查,而第一个(同步)释放后可以立即进入信号量。

异步选项使用的资源比同步版本少,但实际同步比同步版本慢。因此,这取决于您的具体需求、可扩展性或速度。


您可以通过降低 100ms 的超时时间进行优化,从而使异步选项越来越接近同步版本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    • 2011-12-13
    • 1970-01-01
    • 1970-01-01
    • 2015-01-04
    • 1970-01-01
    相关资源
    最近更新 更多