Как я могу создать систему Mutex в C # - PullRequest
14 голосов
/ 02 февраля 2010

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

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

Ответы [ 4 ]

29 голосов
/ 24 июня 2010

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

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

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

Чтобы создать общесистемный мьютекс, вызовите конструктор System.Threading.Mutex, который принимает строку в качестве аргумента.Это также известно как «именованный» мьютекс.Чтобы увидеть, существует ли он, я не могу найти более изящный метод, чем попытка 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.
}

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

_mutey.ReleaseMutex();

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

[EDIT]

В качестве дополнительного примечания к последнему предложению, описывающему мьютекс, который был оставлен, когда другой поток получает мьютекс, будет выдано исключение System.Threading.AbandonedMutexException, сообщающее ему, что он был найден в оставленном состоянии.* [РЕДАКТИРОВАТЬ ВТОРОЕ]

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

3 голосов
/ 02 февраля 2010

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

0 голосов
/ 10 февраля 2016

Мне не повезло с использованием System Mutex, описанной выше, с использованием Mono под Linux. Я, вероятно, просто делаю что-то не так, но следующее работает хорошо и хорошо очищается, если процесс неожиданно завершается (kill -9). Было бы интересно услышать комментарии или критические замечания.

class SocketMutex{
    private Socket _sock;
    private IPEndPoint _ep;
    public SocketMutex(){
        _ep = new IPEndPoint(IPAddress.Parse( "127.0.0.1" ), 7177);
        _sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        _sock.ExclusiveAddressUse = true;  // most critical if you want this to be a system wide mutex
    }

    public bool GetLock(){
        try{        
            _sock.Bind(_ep); // 'SocketException: Address already in use'
        }catch(SocketException se){
            Console.Error.WriteLine ("SocketMutex Exception: " se.Message);
            return false;
        }
        return true;

    }
}
0 голосов
/ 02 февраля 2010

не видя ваш код, сложно дать конкретный совет, но в c #

MSDN

есть класс мьютекса
...