Sam*_*ron 365 c# concurrency mutex
Mutex类被误解了,而Global mutex则更是如此.
在创建全局互斥锁时使用什么是好的,安全的模式?
一个会起作用的
Sam*_*ron 393
我想确保它在那里,因为它很难做到:
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
dee*_*ee1 125
使用接受的答案我创建了一个帮助器类,因此您可以使用与使用Lock语句类似的方式使用它.只是想我会分享.
使用:
using (new SingleGlobalInstance(1000)) //1000ms timeout on global lock
{
//Only 1 of these runs at a time
RunSomeStuff();
}
Run Code Online (Sandbox Code Playgroud)
辅助类:
class SingleGlobalInstance : IDisposable
{
//edit by user "jitbit" - renamed private fields to "_"
public bool _hasHandle = false;
Mutex _mutex;
private void InitMutex()
{
string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value;
string mutexId = string.Format("Global\\{{{0}}}", appGuid);
_mutex = new Mutex(false, mutexId);
var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
var securitySettings = new MutexSecurity();
securitySettings.AddAccessRule(allowEveryoneRule);
_mutex.SetAccessControl(securitySettings);
}
public SingleGlobalInstance(int timeOut)
{
InitMutex();
try
{
if(timeOut < 0)
_hasHandle = _mutex.WaitOne(Timeout.Infinite, false);
else
_hasHandle = _mutex.WaitOne(timeOut, false);
if (_hasHandle == false)
throw new TimeoutException("Timeout waiting for exclusive access on SingleInstance");
}
catch (AbandonedMutexException)
{
_hasHandle = true;
}
}
public void Dispose()
{
if (_mutex != null)
{
if (_hasHandle)
_mutex.ReleaseMutex();
_mutex.Close();
}
}
}
Run Code Online (Sandbox Code Playgroud)
Van*_*yen 12
当在2个不同用户下运行的2个进程同时尝试初始化互斥锁时,接受的答案中存在竞争条件.在第一个进程初始化互斥锁之后,如果第二个进程在第一个进程将访问规则设置为每个进程之前尝试初始化互斥锁,则第二个进程将抛出未经授权的异常.
请参阅下面的更正答案:
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 );
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);
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 the mutex was abandoned in another process, it will still get aquired
hasHandle = true;
}
// Perform your work here.
}
finally
{
// edited by acidzombie24, added if statemnet
if(hasHandle)
mutex.ReleaseMutex();
}
}
}
Run Code Online (Sandbox Code Playgroud)
Lia*_*iam 10
如果另一个实例已在运行,此示例将在5秒后退出.
// unique id for global mutex - Global prefix means it is global to the machine
const string mutex_id = "Global\\{B1E7934A-F688-417f-8FCB-65C3985E9E27}";
static void Main(string[] args)
{
using (var mutex = new Mutex(false, mutex_id))
{
try
{
try
{
if (!mutex.WaitOne(TimeSpan.FromSeconds(5), false))
{
Console.WriteLine("Another instance of this program is running");
Environment.Exit(0);
}
}
catch (AbandonedMutexException)
{
// Log the fact the mutex was abandoned in another process, it will still get aquired
}
// Perform your work here.
}
finally
{
mutex.ReleaseMutex();
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 8
Mutex和WinApi CreateMutex()都不适合我.
另一种解决方案:
static class Program
{
[STAThread]
static void Main()
{
if (SingleApplicationDetector.IsRunning()) {
return;
}
Application.Run(new MainForm());
SingleApplicationDetector.Close();
}
}
Run Code Online (Sandbox Code Playgroud)
而且SingleApplicationDetector
:
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Threading;
public static class SingleApplicationDetector
{
public static bool IsRunning()
{
string guid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString();
var semaphoreName = @"Global\" + guid;
try {
__semaphore = Semaphore.OpenExisting(semaphoreName, SemaphoreRights.Synchronize);
Close();
return true;
}
catch (Exception ex) {
__semaphore = new Semaphore(0, 1, semaphoreName);
return false;
}
}
public static void Close()
{
if (__semaphore != null) {
__semaphore.Close();
__semaphore = null;
}
}
private static Semaphore __semaphore;
}
Run Code Online (Sandbox Code Playgroud)
使用信号量而不是互斥锁的原因:
Mutex类强制执行线程标识,因此互斥锁只能由获取它的线程释放.相比之下,Semaphore类不强制执行线程标识.
归档时间: |
|
查看次数: |
100547 次 |
最近记录: |