Как я могу создать Системное Взаимное исключение в C#

Как я могу создать Взаимное исключение системы/мультипроцесса для координирования нескольких процессов с помощью того же неуправляемого ресурса.

Фон: я записал процедуру, которая использует принтер Файла, который может только использоваться одним процессом за один раз. Если бы я хотел использовать его на нескольких программах, работающих на компьютере, то мне был бы нужен способ синхронизировать это через систему.

14
задан C. Ross 2 February 2010 в 18:56
поделиться

2 ответа

Вы можете использовать класс System.Threading.Mutex, который имеет метод OpenExisting для открытия именованного системного мьютекса.

Это не отвечает на вопрос:

Как я могу создать системный/многопроцессный мьютекс

Чтобы создать общесистемный мьютекс, вызовите конструктор System.Threading.Mutex, который принимает в качестве аргумента строку. Это также известно как "именованный" мьютекс. Чтобы проверить, существует ли он, я не могу найти более изящного метода, чем try catch:

System.Threading.Mutex _mutey = null;
try
{
    _mutey = System.Threading.Mutex.OpenExisting("mutex_name");
    //we got Mutey and can try to obtain a lock by waitone
    _mutey.WaitOne();
}
catch 
{
    //the specified mutex doesn't exist, we should create it
    _mutey = new System.Threading.Mutex("mutex_name"); //these names need to match.
}

Теперь, чтобы быть хорошим программистом, вы должны при завершении программы освободить этот мьютекс

_mutey.ReleaseMutex();

или оставить его, в этом случае он будет назван "брошенным" при выходе вашего потока и позволит другому процессу создать его.

[EDIT]

В качестве примечания к последнему предложению, описывающему оставленный мьютекс, когда другой поток приобретает мьютекс, будет выброшено исключение System.Threading.AbandonedMutexException, сообщающее ему, что он был найден в оставленном состоянии.

[EDIT TWO]

Я не уверен, почему я ответил на этот вопрос таким образом много лет назад; существует (и существовала) перегрузка конструктора, которая гораздо лучше проверяет наличие существующего мьютекса. На самом деле, код, который я привел, похоже, имеет состояние гонки! (И стыд вам всем за то, что не поправили меня! :-P )

Вот условие гонки: Представьте себе два процесса, они оба пытаются открыть существующий мьютекс одновременно, и оба доходят до секции кода catch. Затем один из процессов создает мьютекс и живет долго и счастливо. Другой процесс, однако, пытается создать мьютекс, но на этот раз он уже создан! Эта проверка/создание мьютекса должна быть атомарной.

http://msdn.microsoft.com/en-us/library/bwe34f1k(v=vs.90).aspx

Итак...

var requestInitialOwnership = false;
bool mutexWasCreated;
Mutex m = new Mutex(requestInitialOwnership, 
         "MyMutex", out mutexWasCreated);

Я думаю, что фокус здесь в том, что кажется, что у вас есть возможность, которой на самом деле нет (по-моему, это похоже на недостаток дизайна). Вы иногда не можете определить, владеете ли вы мьютексом, если передаете true для requestInitialOwnership. Если вы передадите true и окажется, что ваш вызов создал мьютекс, то, очевидно, вы владеете им (подтверждено документацией). Если вы передали true и ваш вызов не создал мьютекс, все, что вы знаете, это то, что мьютекс уже был создан, вы не знаете, владеет ли им в настоящее время какой-то другой процесс или поток, который, возможно, создал мьютекс. Поэтому вы должны WaitOne, чтобы убедиться, что он у вас есть. Но тогда сколько Release вы сделаете? Если мьютекс принадлежал какому-то другому процессу, когда вы его получили, то только ваш явный вызов WaitOne должен быть Released. Если ваш вызов конструктора вызвал владение мьютексом, и вы вызвали WaitOne явно, то вам потребуется два Releases.

Я запишу эти слова в код:

var requestInitialOwnership = true; /*This appears to be a mistake.*/
bool mutexWasCreated;
Mutex m = new Mutex(requestInitialOwnership, 
         "MyMutex", out mutexWasCreated);

if ( !mutexWasCreated )
{
    bool calledWaitOne = false;
    if ( ! iOwnMutex(m) ) /*I don't know of a method like this*/
    {
        calledWaitOne = true;
        m.WaitOne();
    }

    doWorkWhileHoldingMutex();

    m.Release();
    if ( calledWaitOne )
    {
        m.Release();
    }
}

Поскольку я не вижу способа проверить, владеете ли вы мьютексом в данный момент, я настоятельно рекомендую передать false в конструктор, чтобы вы знали, что не владеете мьютексом, и знали, сколько раз вызывать Release.

29
ответ дан 1 December 2019 в 08:42
поделиться

Вы можете использовать класс System.Threading.mutex , который имеет метод OpenExisting , чтобы открыть именованную систему Mutex.

3
ответ дан 1 December 2019 в 08:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: