Compartilhar via


Mutex Classe

Definição

Um primitivo de sincronização que também pode ser usado para sincronização entre processos.

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
Herança
Herança
Atributos

Exemplos

Este exemplo mostra como um objeto local Mutex é usado para sincronizar o acesso a um recurso protegido. Como cada thread de chamada é bloqueado até adquirir a propriedade do mutex, ele deve chamar o ReleaseMutex método para liberar a propriedade do mutex.

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

No exemplo a seguir, cada thread chama o WaitOne(Int32) método para adquirir o mutex. Se o intervalo de tempo limite decorrer, o método retornará falsee o thread não adquirirá o mutex nem obterá acesso ao recurso protegido pelo mutex. O ReleaseMutex método é chamado apenas pelo thread que adquire o mutex.

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

Comentários

Quando dois ou mais threads precisam acessar um recurso compartilhado ao mesmo tempo, o sistema precisa de um mecanismo de sincronização para garantir que apenas um thread por vez use o recurso. Mutex é um primitivo de sincronização que concede acesso exclusivo ao recurso compartilhado a apenas um thread. Se um thread adquirir um mutex, o segundo thread que deseja adquirir esse mutex será suspenso até que o primeiro thread libere o mutex.

Importante

Esse tipo implementa a interface IDisposable. Quando você terminar de usar o tipo, deverá descartá-lo direta ou indiretamente. Para descartar o tipo diretamente, chame o método Dispose dele em um bloco try/catch. Para descartá-lo indiretamente, use um constructo de linguagem como using ( em C#) ou Using (em Visual Basic). Saiba mais na seção "Como usar um objeto que implementa IDisposable" no tópico da interface IDisposable.

Você pode usar o WaitHandle.WaitOne método para solicitar a propriedade de um mutex. O thread de chamada é bloqueado até que ocorra um dos seguintes:

  • O mutex é sinalizado para indicar que ele não é de propriedade. Quando isso acontece, o WaitOne método retorna truee o thread de chamada assume a propriedade do mutex e acessa o recurso protegido pelo mutex. Quando terminar de acessar o recurso, o thread deverá chamar o ReleaseMutex método para liberar a propriedade do mutex. O primeiro exemplo na seção Exemplos ilustra esse padrão.

  • O intervalo de tempo limite especificado na chamada para um WaitOne método que tem um millisecondsTimeout parâmetro ou timeout passou. Quando isso acontece, o WaitOne método retorna falsee o thread de chamada não faz mais nenhuma tentativa de adquirir a propriedade do mutex. Nesse caso, você deve estruturar seu código para que o acesso ao recurso protegido pelo mutex seja negado ao thread de chamada. Como o thread nunca adquiriu a propriedade do mutex, ele não deve chamar o ReleaseMutex método . O segundo exemplo na seção Exemplos ilustra esse padrão.

A Mutex classe impõe a identidade do thread, de modo que um mutex só pode ser liberado pelo thread que a adquiriu. Por outro lado, a Semaphore classe não impõe a identidade do thread. Um mutex também pode ser passado entre os limites de domínio do aplicativo.

O thread que possui um mutex pode solicitar o mesmo mutex em chamadas repetidas para WaitOne sem bloquear sua execução. No entanto, o thread deve chamar o ReleaseMutex método o mesmo número de vezes para liberar a propriedade do mutex.

Como a Mutex classe herda de WaitHandle, você também pode chamar os métodos estáticos WaitHandle.WaitAll e WaitHandle.WaitAny para sincronizar o acesso a um recurso protegido.

Se um thread for encerrado ao possuir um mutex, o mutex será considerado abandonado. O estado do mutex é definido como sinalizado e o próximo thread de espera obtém a propriedade. A partir da versão 2.0 do .NET Framework, um AbandonedMutexException é lançado no próximo thread que adquire o mutex abandonado. Antes da versão 2.0 do .NET Framework, nenhuma exceção era gerada.

Cuidado

Um mutex abandonado geralmente indica um erro grave no código. Quando um thread é encerrado sem liberar o mutex, as estruturas de dados protegidas pelo mutex podem não estar em um estado consistente. O próximo thread a solicitar a propriedade do mutex poderá lidar com essa exceção e continuar, se a integridade das estruturas de dados puder ser verificada.

No caso de um mutex de todo o sistema, um mutex abandonado pode indicar que um aplicativo foi finalizado abruptamente (por exemplo, usando o Gerenciador de Tarefas do Windows).

Os mutexes são de dois tipos: mutexes locais, que não têm nome e mutexes do sistema nomeados. Um mutex local existe somente dentro de seu processo. Ele pode ser usado por qualquer thread em seu processo que tenha uma referência ao Mutex objeto que representa o mutex. Cada objeto sem nome Mutex representa um mutex local separado.

Os mutexes de sistema nomeados são visíveis em todo o sistema operacional e podem ser usados para sincronizar as atividades dos processos. Você pode criar um Mutex objeto que representa um mutex do sistema nomeado usando um construtor que aceita um nome. O objeto do sistema operacional pode ser criado ao mesmo tempo ou pode existir antes da criação do Mutex objeto. Você pode criar vários objetos Mutex que representam o mesmo mutex de sistema nomeado, e você pode usar o método OpenExisting para abrir um mutex de sistema nomeado existente.

Observação

Em um servidor que está executando os Serviços de Terminal, um mutex de sistema nomeado pode ter dois níveis de visibilidade. Se seu nome começar com o prefixo Global\, o mutex ficará visível em todas as sessões de servidor de terminal. Se seu nome começar com o prefixo Local\, o mutex ficará visível somente na sessão do servidor de terminal em que foi criado. Nesse caso, um mutex separado com o mesmo nome pode existir em cada uma das outras sessões de servidor de terminal no servidor. Se você não especificar um prefixo ao criar um mutex nomeado, ele usará o prefixo Local\. Em uma sessão de servidor de terminal, dois mutexes cujos nomes diferem apenas por seus prefixos são mutexes separados e ambos são visíveis para todos os processos na sessão do servidor terminal. Ou seja, os nomes Global\ de prefixo e Local\ descrevem o escopo do nome mutex em relação às sessões do servidor de terminal, não em relação aos processos.

Cuidado

Por padrão, um mutex nomeado não é restrito ao usuário que o criou. Outros usuários podem ser capazes de abrir e usar o mutex, incluindo interferir no mutex inserindo o mutex e não saindo dele. Em sistemas operacionais semelhantes ao Unix, o sistema de arquivos é usado na implementação de mutexes nomeados e outros usuários podem interferir em mutexes nomeados de maneiras mais significativas. No Windows, para restringir o acesso a usuários específicos, você pode usar uma sobrecarga de construtor ou MutexAcl e passar um MutexSecurity ao criar o mutex nomeado. Em sistemas operacionais semelhantes ao Unix, atualmente não há como restringir o acesso a um mutex nomeado. Evite usar mutexes nomeados sem restrições de acesso em sistemas que podem ter usuários não confiáveis executando código.

A barra invertida (\) é um caractere reservado em um nome mutex. Não use uma barra invertida (\) em um nome mutex, exceto conforme especificado na anotação sobre como usar mutexes em sessões de servidor de terminal. Caso contrário, uma DirectoryNotFoundException pode ser gerada, mesmo que o nome do mutex represente um arquivo existente.

Construtores

Mutex()

Inicializa uma nova instância da classe Mutex com propriedades padrão.

Mutex(Boolean)

Inicializa uma nova instância da classe Mutex com um valor booliano que indica se o thread de chamada deve ter a propriedade inicial do mutex.

Mutex(Boolean, String)

Inicializa uma nova instância da classe Mutex com um valor booliano que indica se o thread de chamada deve ter uma propriedade inicial do mutex e uma cadeia de caracteres que é o nome do mutex.

Mutex(Boolean, String, Boolean)

Inicializa uma nova instância da classe Mutex com um valor booliano que indica se o thread de chamada deve ter a propriedade inicial de mutex, uma cadeia de caracteres que é o nome do mutex e um valor booliano que, quando o método retorna, indica se o thread de chamada foi concedido a propriedade inicial do mutex.

Mutex(Boolean, String, Boolean, MutexSecurity)

Inicializa uma nova instância da classe Mutex com um valor booliano que indica se o thread de chamada deve ter a propriedade inicial de mutex, uma cadeia de caracteres que é o nome do mutex, uma variável booliana que, quando o método retorna, indica se o thread de chamada foi concedido a propriedade inicial de mutex e a segurança de controle de acesso a ser aplicado ao mutex nomeado.

Campos

WaitTimeout

Indica que uma operação WaitAny(WaitHandle[], Int32, Boolean) atingiu o tempo limite antes que algum dos identificadores de espera fosse sinalizado. Este campo é constante.

(Herdado de WaitHandle)

Propriedades

Handle
Obsoleto.
Obsoleto.

Obtém ou define o identificador de sistema operacional nativo.

(Herdado de WaitHandle)
SafeWaitHandle

Obtém ou define o identificador de sistema operacional nativo.

(Herdado de WaitHandle)

Métodos

Close()

Libera todos os recursos mantidos pelo WaitHandle atual.

(Herdado de WaitHandle)
CreateObjRef(Type)

Cria um objeto que contém todas as informações relevantes necessárias para gerar um proxy usado para se comunicar com um objeto remoto.

(Herdado de MarshalByRefObject)
Dispose()

Libera todos os recursos usados pela instância atual da classe WaitHandle.

(Herdado de WaitHandle)
Dispose(Boolean)

Quando substituído em uma classe derivada, libera os recursos não gerenciados usados pelo WaitHandle e, opcionalmente, libera os recursos gerenciados.

(Herdado de WaitHandle)
Equals(Object)

Determina se o objeto especificado é igual ao objeto atual.

(Herdado de Object)
GetAccessControl()

Obtém um objeto MutexSecurity que representa a segurança do controle de acesso para o mutex nomeado.

GetHashCode()

Serve como a função de hash padrão.

(Herdado de Object)
GetLifetimeService()
Obsoleto.

Recupera o objeto de serviço de tempo de vida atual que controla a política de ciclo de vida para esta instância.

(Herdado de MarshalByRefObject)
GetType()

Obtém o Type da instância atual.

(Herdado de Object)
InitializeLifetimeService()
Obsoleto.

Obtém um objeto de serviço de tempo de vida para controlar a política de tempo de vida para essa instância.

(Herdado de MarshalByRefObject)
MemberwiseClone()

Cria uma cópia superficial do Object atual.

(Herdado de Object)
MemberwiseClone(Boolean)

Cria uma cópia superficial do objeto MarshalByRefObject atual.

(Herdado de MarshalByRefObject)
OpenExisting(String)

Abre o mutex nomeado especificado, caso ele já exista.

OpenExisting(String, MutexRights)

Abre o mutex nomeado especificado, caso ele já exista, com o acesso de segurança desejado.

ReleaseMutex()

Libera o Mutex uma vez.

SetAccessControl(MutexSecurity)

Define a segurança de controle de acesso para um mutex de sistema nomeado.

ToString()

Retorna uma cadeia de caracteres que representa o objeto atual.

(Herdado de Object)
TryOpenExisting(String, Mutex)

Abre o mutex nomeado especificado, quando ele já existe e retorna um valor que indica se a operação foi bem-sucedida.

TryOpenExisting(String, MutexRights, Mutex)

Se o mutex nomeado especificado já existe, abre-o com o acesso de segurança desejado e retorna um valor que indica se a operação foi bem-sucedida.

WaitOne()

Bloqueia o thread atual até que o WaitHandle atual receba um sinal.

(Herdado de WaitHandle)
WaitOne(Int32)

Bloqueia o thread atual até que o WaitHandle atual receba um sinal, usando um inteiro com sinal de 32 bits para especificar o intervalo de tempo em milissegundos.

(Herdado de WaitHandle)
WaitOne(Int32, Boolean)

Bloqueia o thread atual até que o WaitHandle atual receba um sinal, usando um inteiro com sinal de 32 bits para especificar o intervalo de tempo e especificar se sairá do domínio de sincronização antes da espera.

(Herdado de WaitHandle)
WaitOne(TimeSpan)

Bloqueia o thread atual até que a instância atual receba um sinal, usando um TimeSpan para especificar o intervalo de tempo.

(Herdado de WaitHandle)
WaitOne(TimeSpan, Boolean)

Bloqueia o thread atual até que a instância atual receba um sinal, usando um TimeSpan para especificar o intervalo de tempo e especificar se sairá do domínio de sincronização antes da espera.

(Herdado de WaitHandle)

Implantações explícitas de interface

IDisposable.Dispose()

Esta API dá suporte à infraestrutura do produto e não deve ser usada diretamente do seu código.

Libera todos os recursos usados pelo WaitHandle.

(Herdado de WaitHandle)

Métodos de Extensão

GetAccessControl(Mutex)

Retorna os descritores de segurança para o mutex especificado.

SetAccessControl(Mutex, MutexSecurity)

Define os descritores de segurança para o mutex especificado.

GetSafeWaitHandle(WaitHandle)

Obtém o identificador seguro para um identificador de espera nativo do sistema operacional.

SetSafeWaitHandle(WaitHandle, SafeWaitHandle)

Define um identificador seguro para um identificador de espera do sistema operacional nativo.

Aplica-se a

Acesso thread-safe

Este tipo é thread-safe.

Confira também