【问题标题】:Why does deadlock occur on calling Semaphore.WaitOne?为什么调用 Semaphore.WaitOne 会出现死锁?
【发布时间】:2020-06-09 01:01:10
【问题描述】:

以下代码中的run() 函数同时从其他线程调用。根据应用程序的一般设计,在任何时候,任何行都可能发生 ThreadAbortException,这是我无法更改的。

我有时会在拨打pool.Release() 时收到SemaphoreFullException。我认为如果在调用“pool.WaitOne()”时发生线程中止异常,就会发生这种情况。在我的调试尝试中,发生 SemaphoreFullException 后,运行代码没有问题。在该异常之后,pool.WaitOne() 调用和其他操作按预期工作。

在我的本地调试会话期间,我无法遇到死锁情况。但是,在远程计算机中,我的代码出现了死锁。我使用远程调试器附加该进程,并看到执行被锁定在pool.WaitOne(); 行上。

我无法弄清楚这是怎么发生的,以及我做错了什么。非常感谢任何帮助。

private static object poolLocker = new object();
private static Semaphore _pool;
private static Semaphore pool
{
    get
    {
       if (_pool == null)
           lock (poolLocker)
       if (_pool == null)
       {
           int count = myMaximumThreadCount;
           _pool = new Semaphore(count, count);
       }
       return _pool;
    }
}

private void run()
{
    try
    {
        pool.WaitOne();

        do_something_that_may_throw_exception();
    }
    finally
    {
        try
        {
            pool.Release();
        }
        catch (SemaphoreFullException) { }
    }
}

【问题讨论】:

  • 静默隐藏异常的代码(空的catch 块)不会帮助您进行调查
  • @Damien_The_Unbeliever 谢谢你的建议。我更改了该部分只是为了捕获 SemaphoreFullException,并且在远程计算机上发生了相同的死锁。报告所有未处理的异常;没有报告异常。

标签: c# deadlock semaphore


【解决方案1】:

尝试将pool属性中信号量对象的初始化更改为:

private static Semaphore pool
{
    get
    {
       if (_pool == null)
           lock (poolLocker)
       if (_pool == null)
       {
           int count = myMaximumThreadCount;
           _pool = new Semaphore(0, count);
       }
       return _pool;
    }
}

此信号量的初始计数应设置为零。

【讨论】:

    【解决方案2】:

    我找到了死锁的原因;这与我提出的问题无关,所以这是一个糟糕的问题,对此感到抱歉。问题中的代码似乎没有问题。

    原因:在 do_something_that_may_throw_exception() 函数中,调用了 C++ 库的外部函数。当 C++ 函数发生错误时,会引发 SEHException。但是,在我的尝试中,只能在具有 HandleProcessCorruptedStateExceptions 和 SecurityCritical 属性的函数中捕获此异常。该函数恰好调用了问题的 run() 函数。但是,run() 函数的 finally 部分更新执行了! 此外,如果您有 using(IDisposable object){ ... } 并且 SEHException 发生在其中;不会调用对象的 Dispose() 函数。

    我使用以下函数来调用 C++ 函数;一切正常:

    SafeCall(()=> call_external_cpp_function());
    
    [HandleProcessCorruptedStateExceptions]
    [SecurityCritical]
    internal static void SafeCall(Action action)
    {
        try
        {
            action();
        }
        catch (System.Threading.ThreadAbortException) { throw; }
        catch (System.Threading.ThreadInterruptedException) { throw; }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-19
      相关资源
      最近更新 更多