Je veux m'assurer que c'est là-bas, car il est si difficile de bien faire les choses:
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
de vérifiercreatedNew
et d'ajouter à l'mutex.Dispose()
intérieurfinally
. Je ne peux pas l'expliquer clairement (je ne connais pas la raison) en ce moment, mais je me suis retrouvé dans une situation où je suismutex.WaitOne
revenutrue
après êtrecreatedNew
devenufalse
(j'ai acquis le mutex dans le courantAppDomain
, puis j'ai chargé un nouveauAppDomain
et j'ai exécuté le même code à partir de à l'intérieur).exitContext = false
-ce que ça fait quelque chosemutex.WaitOne(5000, false)
? On dirait qu'il ne pouvait provoquer une assertion dans CoreCLR , 2. Si se demander, dans ce quelqu'unMutex
constructeur de », la raison pour laquelleinitiallyOwned
estfalse
partiellement expliquée par cet article MSDN .En utilisant la réponse acceptée, je crée une classe d'assistance afin que vous puissiez l'utiliser de la même manière que vous utiliseriez l'instruction Lock. Je pensais juste partager.
Utilisation:
Et la classe d'assistance:
la source
< 0
lieu de<= 0
._mutex.Close()
au lieu de_mutex.Dispose()
la méthode Dispose fonctionnait pour moi. L'erreur a été provoquée en essayant de supprimer le WaitHandle sous-jacent.Mutex.Close()
dispose des ressources sous-jacentes.Il y a une condition de concurrence critique dans la réponse acceptée lorsque 2 processus s'exécutant sous 2 utilisateurs différents tentent d'initialiser le mutex en même temps. Une fois que le premier processus a initialisé le mutex, si le deuxième processus tente d'initialiser le mutex avant que le premier processus ne définisse la règle d'accès pour tout le monde, une exception non autorisée sera levée par le deuxième processus.
Voir ci-dessous pour la réponse corrigée:
la source
Cet exemple se fermera après 5 secondes si une autre instance est déjà en cours d'exécution.
la source
Ni Mutex ni WinApi CreateMutex () ne fonctionnent pour moi.
Une solution alternative:
Et le
SingleApplicationDetector
:Raison d'utiliser Semaphore au lieu de Mutex:
Réf: Semaphore.OpenExisting ()
la source
Semaphore.OpenExisting
etnew Semaphore
.Parfois, l'apprentissage par l'exemple aide le plus. Exécutez cette application console dans trois fenêtres de console différentes. Vous verrez que l'application que vous avez exécutée en premier acquiert le mutex en premier, tandis que les deux autres attendent leur tour. Appuyez ensuite sur Entrée dans la première application, vous verrez que l'application 2 continue maintenant de fonctionner en acquérant le mutex, mais l'application 3 attend son tour. Après avoir appuyé sur Entrée dans l'application 2, vous verrez que l'application 3 continue. Cela illustre le concept d'un mutex protégeant une section de code à exécuter uniquement par un thread (dans ce cas, un processus) comme l'écriture dans un fichier à titre d'exemple.
la source
Un Mutex mondial ne consiste pas seulement à s'assurer de n'avoir qu'une seule instance d'une application. Personnellement, je préfère utiliser Microsoft.VisualBasic pour garantir une application à instance unique comme décrit dans Quelle est la bonne façon de créer une application WPF à instance unique? (Réponse de Dale Ragan) ... J'ai trouvé qu'il était plus facile de transmettre les arguments reçus au démarrage d'une nouvelle application à l'application initiale à instance unique.
Mais en ce qui concerne un code précédent dans ce fil, je préférerais ne pas créer de Mutex chaque fois que je veux avoir un verrou dessus. Cela pourrait être bien pour une application à instance unique, mais dans d'autres utilisations, il me semble que c'est trop.
C'est pourquoi je suggère plutôt cette implémentation:
Usage:
Mutex Global Wrapper:
Un serveur
la source
Une solution (pour WPF) sans WaitOne car elle peut provoquer une AbandonedMutexException. Cette solution utilise le constructeur Mutex qui renvoie le booléen createdNew pour vérifier si le mutex est déjà créé. Il utilise également le GetType (). GUID donc renommer un exécutable ne permet pas plusieurs instances.
Mutex global vs local voir note dans: https://docs.microsoft.com/en-us/dotnet/api/system.threading.mutex?view=netframework-4.8
Étant donné que Mutex implémente IDisposable, il est libéré automatiquement, mais pour être complet, appelez dispose:
Déplacez tout dans une classe de base et ajoutez le allowEveryoneRule de la réponse acceptée. Ajout également de ReleaseMutex bien qu'il ne semble pas vraiment nécessaire car il est publié automatiquement par le système d'exploitation (et si l'application se bloque et n'appelle jamais ReleaseMutex, auriez-vous besoin de redémarrer?).
la source