গ্লোবাল মুটেক্স কেবলমাত্র একটি অ্যাপ্লিকেশনটির কেবলমাত্র একটি উদাহরণ রয়েছে তা নিশ্চিত করার জন্য নয়। আমি ব্যক্তিগতভাবে মাইক্রোসফ্ট ব্যবহার করতে পছন্দ করি is ভিজুয়ালবাসিক যেমন সিঙ্গল-ইনস্ট্যান্স ডাব্লুপিএফ অ্যাপ্লিকেশন তৈরির সঠিক উপায় কী তা বর্ণিত যেমন একক উদাহরণ অ্যাপ্লিকেশন নিশ্চিত করতে? (ডেল রাগান উত্তর) ... আমি খুঁজে পেয়েছি যে নতুন অ্যাপ্লিকেশন প্রারম্ভিকালে প্রাথমিক একক উদাহরণ অ্যাপ্লিকেশনটিতে প্রাপ্ত তর্কগুলি আরও সহজ।
তবে এই থ্রেডে পূর্ববর্তী কয়েকটি কোড সম্পর্কিত, আমি প্রতিবার লক রাখতে চাইলে কোনও মুটেক্স তৈরি না করা পছন্দ করি। এটি একটি একক উদাহরণের আবেদনের জন্য ভাল হতে পারে তবে অন্য ব্যবহারে আমার কাছে মনে হয় ওভারকিল রয়েছে।
এজন্য আমি পরিবর্তে এই প্রয়োগের পরামর্শ দিই:
ব্যবহার:
static MutexGlobal _globalMutex = null;
static MutexGlobal GlobalMutexAccessEMTP
{
get
{
if (_globalMutex == null)
{
_globalMutex = new MutexGlobal();
}
return _globalMutex;
}
}
using (GlobalMutexAccessEMTP.GetAwaiter())
{
...
}
মুটেক্স গ্লোবাল র্যাপার:
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Threading;
namespace HQ.Util.General.Threading
{
public class MutexGlobal : IDisposable
{
// ************************************************************************
public string Name { get; private set; }
internal Mutex Mutex { get; private set; }
public int DefaultTimeOut { get; set; }
public Func<int, bool> FuncTimeOutRetry { get; set; }
// ************************************************************************
public static MutexGlobal GetApplicationMutex(int defaultTimeOut = Timeout.Infinite)
{
return new MutexGlobal(defaultTimeOut, ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value);
}
// ************************************************************************
public MutexGlobal(int defaultTimeOut = Timeout.Infinite, string specificName = null)
{
try
{
if (string.IsNullOrEmpty(specificName))
{
Name = Guid.NewGuid().ToString();
}
else
{
Name = specificName;
}
Name = string.Format("Global\\{{{0}}}", Name);
DefaultTimeOut = defaultTimeOut;
FuncTimeOutRetry = DefaultFuncTimeOutRetry;
var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
var securitySettings = new MutexSecurity();
securitySettings.AddAccessRule(allowEveryoneRule);
Mutex = new Mutex(false, Name, out bool createdNew, securitySettings);
if (Mutex == null)
{
throw new Exception($"Unable to create mutex: {Name}");
}
}
catch (Exception ex)
{
Log.Log.Instance.AddEntry(Log.LogType.LogException, $"Unable to create Mutex: {Name}", ex);
throw;
}
}
// ************************************************************************
/// <summary>
///
/// </summary>
/// <param name="timeOut"></param>
/// <returns></returns>
public MutexGlobalAwaiter GetAwaiter(int timeOut)
{
return new MutexGlobalAwaiter(this, timeOut);
}
// ************************************************************************
/// <summary>
///
/// </summary>
/// <param name="timeOut"></param>
/// <returns></returns>
public MutexGlobalAwaiter GetAwaiter()
{
return new MutexGlobalAwaiter(this, DefaultTimeOut);
}
// ************************************************************************
/// <summary>
/// This method could either throw any user specific exception or return
/// true to retry. Otherwise, retruning false will let the thread continue
/// and you should verify the state of MutexGlobalAwaiter.HasTimedOut to
/// take proper action depending on timeout or not.
/// </summary>
/// <param name="timeOutUsed"></param>
/// <returns></returns>
private bool DefaultFuncTimeOutRetry(int timeOutUsed)
{
// throw new TimeoutException($"Mutex {Name} timed out {timeOutUsed}.");
Log.Log.Instance.AddEntry(Log.LogType.LogWarning, $"Mutex {Name} timeout: {timeOutUsed}.");
return true; // retry
}
// ************************************************************************
public void Dispose()
{
if (Mutex != null)
{
Mutex.ReleaseMutex();
Mutex.Close();
}
}
// ************************************************************************
}
}
Awaiter
using System;
namespace HQ.Util.General.Threading
{
public class MutexGlobalAwaiter : IDisposable
{
MutexGlobal _mutexGlobal = null;
public bool HasTimedOut { get; set; } = false;
internal MutexGlobalAwaiter(MutexGlobal mutexEx, int timeOut)
{
_mutexGlobal = mutexEx;
do
{
HasTimedOut = !_mutexGlobal.Mutex.WaitOne(timeOut, false);
if (! HasTimedOut) // Signal received
{
return;
}
} while (_mutexGlobal.FuncTimeOutRetry(timeOut));
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
_mutexGlobal.Mutex.ReleaseMutex();
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
disposedValue = true;
}
}
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// ~MutexExAwaiter()
// {
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
// Dispose(false);
// }
// This code added to correctly implement the disposable pattern.
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
// TODO: uncomment the following line if the finalizer is overridden above.
// GC.SuppressFinalize(this);
}
#endregion
}
}
using
চেক করতেcreatedNew
এবংmutex.Dispose()
ভিতরে যুক্ত করতে বাদ দিতে পারেনfinally
। আমি এখনই এটি স্পষ্টভাবে ব্যাখ্যা করতে পারি না (কারণটি আমি জানি না) তবে হয়ে ওঠার পরেmutex.WaitOne
ফিরে এসে নিজেকে এমন পরিস্থিতিতে ফেলেছি (আমি বর্তমানের মধ্যে মিউটেক্সটি অর্জন করেছি এবং তার পরে একটি নতুন কোড লোড করেছি এবং সেখান থেকে একই কোড কার্যকর করা হয়েছে) এটার মধ্যে).true
createdNew
false
AppDomain
AppDomain