Как я могу создать Взаимное исключение системы/мультипроцесса для координирования нескольких процессов с помощью того же неуправляемого ресурса.
Фон: я записал процедуру, которая использует принтер Файла, который может только использоваться одним процессом за один раз. Если бы я хотел использовать его на нескольких программах, работающих на компьютере, то мне был бы нужен способ синхронизировать это через систему.
Вы можете использовать класс 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
должен быть Release
d. Если ваш вызов конструктора вызвал владение мьютексом, и вы вызвали WaitOne
явно, то вам потребуется два Release
s.
Я запишу эти слова в код:
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
.
Вы можете использовать класс System.Threading.mutex
, который имеет метод OpenExisting
, чтобы открыть именованную систему Mutex.