Почему возникает тупик при вызове Semaphore.WaitOne? - PullRequest
0 голосов
/ 25 февраля 2020

Функция run() в следующем коде вызывается из других потоков одновременно. В любое время в любой строке может возникнуть исключение ThreadAbortException в соответствии с общим дизайном приложения, которое я не могу изменить.

Иногда я получаю SemaphoreFullException при вызове pool.Release(). Я думаю, что это происходит, если исключение прерывания потока происходит при вызове "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) { }
    }
}

Ответы [ 2 ]

0 голосов
/ 26 февраля 2020

Я нашел причину тупика; и это не имеет ничего общего с вопросом, который я задал, так что это плохой вопрос, извините за это. Кажется, в коде вопроса нет проблем.

Причина: в функции do_something_that_may_throw_exception () вызывается внешняя функция библиотеки C ++. Когда в функции C ++ происходит ошибка, генерируется исключение SEHException. Однако в моих попытках это исключение может быть перехвачено только в функции, имеющей атрибуты HandleProcessCorruptedStateExceptions и SecurityCritical. И эта функция вызывает функцию run () вопроса. Однако, часть finally функции run () выполняется новее! Кроме того, если у вас есть использование (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);
    }
}
0 голосов
/ 25 февраля 2020

Попробуйте изменить инициализацию объекта семафора в свойстве pool на:

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

Начальный счет для этого семафора должен быть установлен равным нулю.

...