Quero ter certeza de que isso existe, porque é muito difícil acertar:
using System.Runtime.InteropServices; //GuidAttribute
using System.Reflection; //Assembly
using System.Threading; //Mutex
using System.Security.AccessControl; //MutexAccessRule
using System.Security.Principal; //SecurityIdentifier
static void Main(string[] args)
{
// get application GUID as defined in AssemblyInfo.cs
string appGuid =
((GuidAttribute)Assembly.GetExecutingAssembly().
GetCustomAttributes(typeof(GuidAttribute), false).
GetValue(0)).Value.ToString();
// unique id for global mutex - Global prefix means it is global to the machine
string mutexId = string.Format( "Global\\{{{0}}}", appGuid );
// Need a place to store a return value in Mutex() constructor call
bool createdNew;
// edited by Jeremy Wiebe to add example of setting up security for multi-user usage
// edited by 'Marc' to work also on localized systems (don't use just "Everyone")
var allowEveryoneRule =
new MutexAccessRule( new SecurityIdentifier( WellKnownSidType.WorldSid
, null)
, MutexRights.FullControl
, AccessControlType.Allow
);
var securitySettings = new MutexSecurity();
securitySettings.AddAccessRule(allowEveryoneRule);
// edited by MasonGZhwiti to prevent race condition on security settings via VanNguyen
using (var mutex = new Mutex(false, mutexId, out createdNew, securitySettings))
{
// edited by acidzombie24
var hasHandle = false;
try
{
try
{
// note, you may want to time out here instead of waiting forever
// edited by acidzombie24
// mutex.WaitOne(Timeout.Infinite, false);
hasHandle = mutex.WaitOne(5000, false);
if (hasHandle == false)
throw new TimeoutException("Timeout waiting for exclusive access");
}
catch (AbandonedMutexException)
{
// Log the fact that the mutex was abandoned in another process,
// it will still get acquired
hasHandle = true;
}
// Perform your work here.
}
finally
{
// edited by acidzombie24, added if statement
if(hasHandle)
mutex.ReleaseMutex();
}
}
}
using
para verificarcreatedNew
e adicionarmutex.Dispose()
dentrofinally
. Não posso explicar claramente (não sei o motivo) no momento, mas me deparei com uma situação em quemutex.WaitOne
retorneitrue
depois que mecreatedNew
torneifalse
(adquiri o mutex no atualAppDomain
e carreguei um novoAppDomain
e executei o mesmo código de dentro dele).exitContext = false
alguma coisamutex.WaitOne(5000, false)
? Parece que ele só poderia causar uma declaração em CoreCLR , 2. Se alguém está se perguntando, emMutex
's construtor, a razão pela qualinitiallyOwned
éfalse
parcialmente explicada por este artigo MSDN .Usando a resposta aceita, crio uma classe auxiliar para que você possa usá-la da mesma maneira que usaria a instrução Lock. Só pensei em compartilhar.
Usar:
E a classe auxiliar:
fonte
< 0
vez de<= 0
._mutex.Close()
invés de_mutex.Dispose()
funcionou para mim. O erro foi causado ao tentar descartar o WaitHandle subjacente.Mutex.Close()
dispõe dos recursos subjacentes.Há uma condição de corrida na resposta aceita quando 2 processos sendo executados com menos de 2 usuários diferentes tentando inicializar o mutex ao mesmo tempo. Após o primeiro processo inicializar o mutex, se o segundo processo tentar inicializar o mutex antes que o primeiro processo defina a regra de acesso a todos, uma exceção não autorizada será lançada pelo segundo processo.
Veja abaixo a resposta corrigida:
fonte
Este exemplo será encerrado após 5 segundos se outra instância já estiver em execução.
fonte
Nem o Mutex nem o WinApi CreateMutex () funcionam para mim.
Uma solução alternativa:
E o
SingleApplicationDetector
:Razão para usar o Semáforo em vez do Mutex:
Ref: Semaphore.OpenExisting ()
fonte
Semaphore.OpenExisting
enew Semaphore
.Às vezes, aprender pelo exemplo ajuda mais. Execute este aplicativo de console em três janelas diferentes. Você verá que o aplicativo que você executou primeiro adquire o mutex primeiro, enquanto os outros dois estão esperando a vez deles. Em seguida, pressione enter no primeiro aplicativo. Você verá que o aplicativo 2 continua em execução adquirindo o mutex, mas o aplicativo 3 está aguardando sua vez. Depois de pressionar enter no aplicativo 2, você verá que o aplicativo 3 continua. Isso ilustra o conceito de um mutex que protege uma seção de código a ser executada apenas por um encadeamento (neste caso, um processo) como gravar em um arquivo como exemplo.
fonte
Um Mutex global não serve apenas para garantir a existência de apenas uma instância de um aplicativo. Pessoalmente, prefiro usar o Microsoft.VisualBasic para garantir um aplicativo de instância única, como descrito em Qual é a maneira correta de criar um aplicativo WPF de instância única? (Resposta de Dale Ragan) ... Achei mais fácil passar argumentos recebidos na inicialização do novo aplicativo para o aplicativo de instância única inicial.
Mas, com relação a algum código anterior desse segmento, eu preferiria não criar um Mutex toda vez que eu quisesse ter um bloqueio nele. Pode ser bom para um aplicativo de instância única, mas em outro uso parece-me um exagero.
É por isso que sugiro esta implementação:
Uso:
Empacotador Global da Mutex:
Um garçom
fonte
Uma solução (para WPF) sem WaitOne porque pode causar uma AbandonedMutexException. Esta solução usa o construtor Mutex que retorna o booleano createdNew para verificar se o mutex já foi criado. Ele também usa o GetType (). GUID, portanto, renomear um executável não permite várias instâncias.
Mutex global x local, consulte a nota em: https://docs.microsoft.com/en-us/dotnet/api/system.threading.mutex?view=netframework-4.8
Como o Mutex implementa o IDisposable, ele é liberado automaticamente, mas, para completar, chame descarte:
Mova tudo para uma classe base e adicione o allowEveryoneRule da resposta aceita. Também foi adicionado o ReleaseMutex, embora não pareça realmente necessário porque é lançado automaticamente pelo sistema operacional (e se o aplicativo falhar e nunca chamar o ReleaseMutex, você precisaria reiniciar?).
fonte