I want to make sure this is out there, because it's so hard to get right:
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();
}
}
}
shareimprove this answer
edited Oct 15 '18 at 7:35
community wiki
18 revs, 14 users 31%
Sam Saffron
1
you may want to omit using to check createdNew and add mutex.Dispose() inside finally. I can't explain it clearly (I don't know the reason) right now but I've got myself to a situation when mutex.WaitOne returned true after createdNew became false (I acquired the mutex in the current AppDomain and then loaded a new AppDomain and executed the same code from within it). – Sergey.quixoticaxis.Ivanov Feb 7 '17 at 14:44
1. Does exitContext = false do anything in mutex.WaitOne(5000, false)? It looks like it could only cause an assert in CoreCLR, 2. If anyone's wondering, in Mutex's constructor, the reason why initiallyOwned is false is partially explained by this MSDN article. – jrh Nov 1 '17 at 17:30
2
A tip: watch out using Mutex with ASP.NET: "The Mutex class enforces thread identity, so a mutex can be released only by the thread that acquired it. By contrast, the Semaphore class does not enforce thread identity.". An ASP.NET request can be serviced by multiple threads. – Sam Rueby Nov 14 '17 at 20:58
source :
'C#(CSharp) > Etc' 카테고리의 다른 글
Easily write a whole class instance to XML File and read back in (0) | 2018.06.25 |
---|---|
IOException: The process cannot access the file 'file path' because it is being used by another process (0) | 2018.06.23 |
C# memory cache logic (0) | 2018.05.31 |
Write exception log in File. (0) | 2018.05.29 |
c# memory cache (0) | 2018.05.26 |