Поделиться через


Mutex Класс

Определение

Примитив синхронизации, который также может использоваться в межпроцессной синхронизации.

public ref class Mutex sealed : System::Threading::WaitHandle
public sealed class Mutex : System.Threading.WaitHandle
[System.Runtime.InteropServices.ComVisible(true)]
public sealed class Mutex : System.Threading.WaitHandle
type Mutex = class
    inherit WaitHandle
[<System.Runtime.InteropServices.ComVisible(true)>]
type Mutex = class
    inherit WaitHandle
Public NotInheritable Class Mutex
Inherits WaitHandle
Наследование
Наследование
Атрибуты

Примеры

В этом примере показано, как локальный Mutex объект используется для синхронизации доступа к защищенному ресурсу. Так как каждый вызывающий поток блокируется до тех пор, пока он не получит права владения мьютексом, он должен вызвать ReleaseMutex метод , чтобы освободить владение мьютексом.

using System;
using System.Threading;

class Example
{
    // Create a new Mutex. The creating thread does not own the mutex.
    private static Mutex mut = new Mutex();
    private const int numIterations = 1;
    private const int numThreads = 3;

    static void Main()
    {
        // Create the threads that will use the protected resource.
        for(int i = 0; i < numThreads; i++)
        {
            Thread newThread = new Thread(new ThreadStart(ThreadProc));
            newThread.Name = String.Format("Thread{0}", i + 1);
            newThread.Start();
        }

        // The main thread exits, but the application continues to
        // run until all foreground threads have exited.
    }

    private static void ThreadProc()
    {
        for(int i = 0; i < numIterations; i++)
        {
            UseResource();
        }
    }

    // This method represents a resource that must be synchronized
    // so that only one thread at a time can enter.
    private static void UseResource()
    {
        // Wait until it is safe to enter.
        Console.WriteLine("{0} is requesting the mutex", 
                          Thread.CurrentThread.Name);
        mut.WaitOne();

        Console.WriteLine("{0} has entered the protected area", 
                          Thread.CurrentThread.Name);

        // Place code to access non-reentrant resources here.

        // Simulate some work.
        Thread.Sleep(500);

        Console.WriteLine("{0} is leaving the protected area", 
            Thread.CurrentThread.Name);

        // Release the Mutex.
        mut.ReleaseMutex();
        Console.WriteLine("{0} has released the mutex", 
            Thread.CurrentThread.Name);
    }
}
// The example displays output like the following:
//       Thread1 is requesting the mutex
//       Thread2 is requesting the mutex
//       Thread1 has entered the protected area
//       Thread3 is requesting the mutex
//       Thread1 is leaving the protected area
//       Thread1 has released the mutex
//       Thread3 has entered the protected area
//       Thread3 is leaving the protected area
//       Thread3 has released the mutex
//       Thread2 has entered the protected area
//       Thread2 is leaving the protected area
//       Thread2 has released the mutex
Imports System.Threading

Module Example
   ' Create a new Mutex. The creating thread does not own the mutex.
   Private mut As New Mutex()
   Private Const numIterations As Integer = 1
   Private Const numThreads As Integer = 3
   
   Public Sub Main()
        ' Create the threads that will use the protected resource.
        For i As Integer = 0 To numThreads - 1
            Dim newThread As New Thread(AddressOf ThreadProc)
            newThread.Name = String.Format("Thread{0}", i + 1)
            newThread.Start()
        Next

        ' The main thread exits, but the application continues to
        ' run until all foreground threads have exited.
    End Sub

    Private Sub ThreadProc()
        For i As Integer = 0 To numIterations - 1
            UseResource()
        Next
    End Sub

    ' This method represents a resource that must be synchronized
    ' so that only one thread at a time can enter.
    Private Sub UseResource()
        ' Wait until it is safe to enter.
        Console.WriteLine("{0} is requesting the mutex", 
                          Thread.CurrentThread.Name)
        mut.WaitOne()

        Console.WriteLine("{0} has entered the protected area", 
                          Thread.CurrentThread.Name)

        ' Place code to access non-reentrant resources here.

        ' Simulate some work.
        Thread.Sleep(500)

        Console.WriteLine("{0} is leaving the protected area", 
            Thread.CurrentThread.Name)

        ' Release the Mutex.
        mut.ReleaseMutex()
        Console.WriteLine("{0} has released the mutex", 
            Thread.CurrentThread.Name)
   End Sub
End Module
' The example displays output like the following:
'       Thread1 is requesting the mutex
'       Thread2 is requesting the mutex
'       Thread1 has entered the protected area
'       Thread3 is requesting the mutex
'       Thread1 is leaving the protected area
'       Thread1 has released the mutex
'       Thread3 has entered the protected area
'       Thread3 is leaving the protected area
'       Thread3 has released the mutex
'       Thread2 has entered the protected area
'       Thread2 is leaving the protected area
'       Thread2 has released the mutex

В следующем примере каждый поток вызывает WaitOne(Int32) метод для получения мьютекса. Если время ожидания истекает, метод возвращает false, и поток не получает мьютекс и не получает доступа к ресурсу, который защищает мьютекс. Метод ReleaseMutex вызывается только потоком, который получает мьютекс.

using System;
using System.Threading;

class Example
{
    // Create a new Mutex. The creating thread does not own the mutex.
    private static Mutex mut = new Mutex();
    private const int numIterations = 1;
    private const int numThreads = 3;

    static void Main()
    {
        Example ex = new Example();
        ex.StartThreads();
    }

     private void StartThreads()
     {
        // Create the threads that will use the protected resource.
        for(int i = 0; i < numThreads; i++)
        {
            Thread newThread = new Thread(new ThreadStart(ThreadProc));
            newThread.Name = String.Format("Thread{0}", i + 1);
            newThread.Start();
        }

        // The main thread returns to Main and exits, but the application continues to
        // run until all foreground threads have exited.
    }

    private static void ThreadProc()
    {
        for(int i = 0; i < numIterations; i++)
        {
            UseResource();
        }
    }

    // This method represents a resource that must be synchronized
    // so that only one thread at a time can enter.
    private static void UseResource()
    {
        // Wait until it is safe to enter, and do not enter if the request times out.
        Console.WriteLine("{0} is requesting the mutex", Thread.CurrentThread.Name);
        if (mut.WaitOne(1000)) {
           Console.WriteLine("{0} has entered the protected area", 
               Thread.CurrentThread.Name);
   
           // Place code to access non-reentrant resources here.
   
           // Simulate some work.
           Thread.Sleep(5000);
   
           Console.WriteLine("{0} is leaving the protected area", 
               Thread.CurrentThread.Name);
   
           // Release the Mutex.
              mut.ReleaseMutex();
           Console.WriteLine("{0} has released the mutex", 
                             Thread.CurrentThread.Name);
        }
        else {
           Console.WriteLine("{0} will not acquire the mutex", 
                             Thread.CurrentThread.Name);
        }
    }

    ~Example()
    {
       mut.Dispose();
    }
}
// The example displays output like the following:
//       Thread1 is requesting the mutex
//       Thread1 has entered the protected area
//       Thread2 is requesting the mutex
//       Thread3 is requesting the mutex
//       Thread2 will not acquire the mutex
//       Thread3 will not acquire the mutex
//       Thread1 is leaving the protected area
//       Thread1 has released the mutex
Imports System.Threading

Class Example
   ' Create a new Mutex. The creating thread does not own the mutex.
   Private mut As New Mutex()
   Private Const numIterations As Integer = 1
   Private Const numThreads As Integer = 3

   Public Shared Sub Main()
      Dim ex As New Example()
      ex.StartThreads()
   End Sub
   
   Private Sub StartThreads()
        ' Create the threads that will use the protected resource.
        For i As Integer = 0 To numThreads - 1
            Dim newThread As New Thread(AddressOf ThreadProc)
            newThread.Name = String.Format("Thread{0}", i + 1)
            newThread.Start()
        Next

        ' The main thread returns to Main and exits, but the application continues to
        ' run until all foreground threads have exited.
   End Sub

   Private Sub ThreadProc()
        For i As Integer = 0 To numIterations - 1
            UseResource()
        Next
   End Sub

   ' This method represents a resource that must be synchronized
   ' so that only one thread at a time can enter.
   Private Sub UseResource()
        ' Wait until it is safe to enter.
        Console.WriteLine("{0} is requesting the mutex", 
                          Thread.CurrentThread.Name)
        If mut.WaitOne(1000) Then
           Console.WriteLine("{0} has entered the protected area", 
               Thread.CurrentThread.Name)
   
           ' Place code to access non-reentrant resources here.
   
           ' Simulate some work.
           Thread.Sleep(5000)
   
           Console.WriteLine("{0} is leaving the protected area", 
               Thread.CurrentThread.Name)
   
           ' Release the Mutex.
           mut.ReleaseMutex()
           Console.WriteLine("{0} has released the mutex", 
                             Thread.CurrentThread.Name)
        Else
           Console.WriteLine("{0} will not acquire the mutex", 
                             Thread.CurrentThread.Name)
        End If
   End Sub
   
   Protected Overrides Sub Finalize()
      mut.Dispose()
   End Sub
End Class
' The example displays output like the following:
'       Thread1 is requesting the mutex
'       Thread1 has entered the protected area
'       Thread2 is requesting the mutex
'       Thread3 is requesting the mutex
'       Thread2 will not acquire the mutex
'       Thread3 will not acquire the mutex
'       Thread1 is leaving the protected area
'       Thread1 has released the mutex

Комментарии

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

Важно!

Этот тип реализует интерфейс IDisposable. По окончании использования выдаленную ему память следует прямо или косвенно освободить. Чтобы сделать это прямо, вызовите его метод Dispose в блоке try/catch. Чтобы сделать это косвенно, используйте языковые конструкции, такие как using (в C#) или Using (в Visual Basic). Дополнительные сведения см. в разделе "Использование объекта, реализующего IDisposable" в статье об интерфейсе IDisposable.

Метод можно использовать для WaitHandle.WaitOne запроса владения мьютексом. Вызывающий поток блокируется, пока не произойдет одно из следующих действий:

  • Мьютекс получает сигнал о том, что он не принадлежит. В этом случае WaitOne метод возвращает true, а вызывающий поток принимает на себя владение мьютексом и обращается к ресурсу, защищенному мьютексом. Завершив доступ к ресурсу, поток должен вызвать ReleaseMutex метод , чтобы освободить владение мьютексом. Первый пример в разделе Примеры иллюстрирует этот шаблон.

  • Истек интервал времени ожидания, указанный в вызове WaitOne метода с параметром millisecondsTimeout или timeout . В этом случае WaitOne метод возвращает false, а вызывающий поток не предпринимает дальнейших попыток получить владение мьютексом. В этом случае следует структурировать код таким образом, чтобы доступ к ресурсу, защищенному мьютексом, был запрещен вызывающему потоку. Так как поток никогда не приобретал права владения мьютексом, он не должен вызывать ReleaseMutex метод . Второй пример в разделе Примеры иллюстрирует этот шаблон.

Класс Mutex применяет удостоверение потока, поэтому мьютекс может быть освобожден только потоком, который его получил. В отличие от этого, Semaphore класс не применяет удостоверение потока. Мьютекс также может передаваться через границы домена приложения.

Поток, владеющий мьютексом, может запрашивать тот же мьютекс в повторяющихся вызовах , WaitOne не блокируя его выполнение. Однако поток должен вызывать ReleaseMutex метод одинаковое количество раз, чтобы освободить владение мьютексом.

Mutex Так как класс наследуется от WaitHandle, можно также вызвать статические WaitHandle.WaitAll методы и для WaitHandle.WaitAny синхронизации доступа к защищенному ресурсу.

Если поток завершается при владении мьютексом, мьютекс считается отмененным. Состояние мьютекса устанавливается в signaled, и следующий ожидая поток получает право собственности. Начиная с версии 2.0 платформа .NET Framework в следующем потоке возникает исключение AbandonedMutexException , которое получает заброшенный мьютекс. До версии 2.0 платформа .NET Framework исключение не было создано.

Внимание!

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

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

Мьютексы бывают двух типов: локальные мьютексы без имени и именованные системные мьютексы. Локальный мьютекс существует только в вашем процессе. Его может использовать любой поток в процессе, имеющий ссылку Mutex на объект, представляющий мьютекс. Каждый неименованный Mutex объект представляет отдельный локальный мьютекс.

Именованные системные мьютексы видны во всей операционной системе и могут использоваться для синхронизации действий процессов. Вы можете создать Mutex объект, представляющий именованный системный мьютекс, с помощью конструктора, принимающего имя. Объект операционной системы может быть создан одновременно или существовать до создания Mutex объекта . Вы можете создать сразу несколько объектов Mutex, представляющих один и тот именованный системный мьютекс, а также открывать именованный системный мьютекс с помощью метода OpenExisting.

Примечание

На сервере, на котором выполняются службы терминалов, именованный системный мьютекс может иметь два уровня видимости. Если его имя начинается с префикса Global\, мьютекс отображается во всех сеансах сервера терминалов. Если его имя начинается с префикса Local\, мьютекс отображается только в сеансе сервера терминалов, где он был создан. В этом случае в каждом из других сеансов сервера терминалов на сервере может существовать отдельный мьютекс с тем же именем. Если префикс не указан при создании именованного мьютекса, он принимает префикс Local\. В сеансе сервера терминалов два мьютекса, имена которых отличаются только префиксами, являются отдельными мьютексами и видны всем процессам в сеансе сервера терминалов. То есть имена префиксов Global\ и Local\ описывают область имени мьютекса относительно сеансов сервера терминалов, а не относительно процессов.

Внимание!

По умолчанию именованный мьютекс не ограничивается пользователем, который его создал. Другие пользователи могут открыть и использовать мьютекс, в том числе вмешиваться в мьютекс, введя мьютекс и не выходя из него. В unix-подобных операционных системах файловая система используется в реализации именованных мьютексов, и другие пользователи могут более значительным образом вмешиваться в именованные мьютексы. В Windows, чтобы ограничить доступ для определенных пользователей, можно использовать перегрузку конструктора или MutexAcl передать в MutexSecurity при создании именованного мьютекса. В операционных системах, подобных Unix, в настоящее время невозможно ограничить доступ к именованному мьютексу. Избегайте использования именованных мьютексов без ограничений доступа в системах, в которых код могут выполнять ненадежные пользователи.

Обратная косая черта (\) — это зарезервированный символ в имени мьютекса. Не используйте обратную косую черту (\) в имени мьютекса, за исключением случаев, указанных в примечании об использовании мьютексов в сеансах сервера терминалов. В противном случае может возникнуть исключение DirectoryNotFoundException, даже если имя мьютекса представляет существующий файл.

Конструкторы

Mutex()

Инициализирует новый экземпляр класса Mutex стандартными свойствами.

Mutex(Boolean)

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

Mutex(Boolean, String)

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

Mutex(Boolean, String, Boolean)

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

Mutex(Boolean, String, Boolean, MutexSecurity)

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

Поля

WaitTimeout

Указывает, что время ожидания операции WaitAny(WaitHandle[], Int32, Boolean) истекло до получения сигнала каким-либо из дескрипторов ожидания. Это поле является константой.

(Унаследовано от WaitHandle)

Свойства

Handle
Устаревшие..
Устаревшие..

Возвращает или задает собственный дескриптор операционной системы.

(Унаследовано от WaitHandle)
SafeWaitHandle

Возвращает или задает собственный дескриптор операционной системы.

(Унаследовано от WaitHandle)

Методы

Close()

Освобождает все ресурсы, удерживаемые текущим объектом WaitHandle.

(Унаследовано от WaitHandle)
CreateObjRef(Type)

Создает объект, который содержит всю необходимую информацию для создания прокси-сервера, используемого для взаимодействия с удаленным объектом.

(Унаследовано от MarshalByRefObject)
Dispose()

Освобождает все ресурсы, используемые текущим экземпляром класса WaitHandle.

(Унаследовано от WaitHandle)
Dispose(Boolean)

При переопределении в производном классе освобождает неуправляемые ресурсы, используемые объектом WaitHandle, и при необходимости освобождает управляемые ресурсы.

(Унаследовано от WaitHandle)
Equals(Object)

Определяет, равен ли указанный объект текущему объекту.

(Унаследовано от Object)
GetAccessControl()

Получает объект MutexSecurity, представляющий безопасность управления доступом для именованного мьютекса.

GetHashCode()

Служит хэш-функцией по умолчанию.

(Унаследовано от Object)
GetLifetimeService()
Устаревшие..

Извлекает объект обслуживания во время существования, который управляет политикой времени существования данного экземпляра.

(Унаследовано от MarshalByRefObject)
GetType()

Возвращает объект Type для текущего экземпляра.

(Унаследовано от Object)
InitializeLifetimeService()
Устаревшие..

Получает объект службы времени существования для управления политикой времени существования для этого экземпляра.

(Унаследовано от MarshalByRefObject)
MemberwiseClone()

Создает неполную копию текущего объекта Object.

(Унаследовано от Object)
MemberwiseClone(Boolean)

Создает неполную копию текущего объекта MarshalByRefObject.

(Унаследовано от MarshalByRefObject)
OpenExisting(String)

Открывает указанный именованный мьютекс, если он уже существует.

OpenExisting(String, MutexRights)

Открывает указанный именованный мьютекс, если он уже существует, с требуемыми правами доступа.

ReleaseMutex()

Освобождает объект Mutex один раз.

SetAccessControl(MutexSecurity)

Задает безопасность управления доступом для именованного системного мьютекса.

ToString()

Возвращает строку, представляющую текущий объект.

(Унаследовано от Object)
TryOpenExisting(String, Mutex)

Открывает указанный именованный мьютекс, если он уже существует, и возвращает значение, указывающее, успешно ли выполнена операция.

TryOpenExisting(String, MutexRights, Mutex)

Открывает указанный именованный мьютекс, если он уже существует, с требуемыми правами доступа, и возвращает значение, указывающее, успешно ли выполнена операция.

WaitOne()

Блокирует текущий поток до получения сигнала объектом WaitHandle.

(Унаследовано от WaitHandle)
WaitOne(Int32)

Блокирует текущий поток до получения текущим дескриптором WaitHandle сигнала, используя 32-разрядное целое число со знаком для указания интервала времени в миллисекундах.

(Унаследовано от WaitHandle)
WaitOne(Int32, Boolean)

Блокирует текущий поток до получения сигнала текущим объектом WaitHandle, используя 32-разрядное целое число со знаком для задания периода времени и указывая, следует ли выйти из домена синхронизации до начала ожидания.

(Унаследовано от WaitHandle)
WaitOne(TimeSpan)

Блокирует текущий поток до получения сигнала текущим экземпляром, используя значение типа TimeSpan для указания интервала времени.

(Унаследовано от WaitHandle)
WaitOne(TimeSpan, Boolean)

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

(Унаследовано от WaitHandle)

Явные реализации интерфейса

IDisposable.Dispose()

Этот API поддерживает инфраструктуру продукта и не предназначен для использования непосредственно из программного кода.

Освобождает все ресурсы, занятые модулем WaitHandle.

(Унаследовано от WaitHandle)

Методы расширения

GetAccessControl(Mutex)

Возвращает дескрипторы безопасности для указанного mutex.

SetAccessControl(Mutex, MutexSecurity)

Задает дескрипторы безопасности для указанного мьютекса

GetSafeWaitHandle(WaitHandle)

Возвращает безопасный дескриптор для собственного дескриптора ожидания операционной системы.

SetSafeWaitHandle(WaitHandle, SafeWaitHandle)

Задает безопасный дескриптор для собственного дескриптора ожидания операционной системы.

Применяется к

Потокобезопасность

Данный тип потокобезопасен.

См. также раздел