Подтвердить что ты не робот

Как создать системный мьютекс в С#

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

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

4b9b3361

Ответ 1

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

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

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

Чтобы создать общесистемный мьютекс, вызовите конструктор 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.

Ответ 2

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

Ответ 3

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

MSDN

Ответ 4

Мне не повезло с использованием описанного выше 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;

    }
}