সি # তে গ্লোবাল মুটেক্স ব্যবহারের জন্য ভাল প্যাটার্নটি কী?


377

মুটেক্স শ্রেণিটি খুব ভুল বোঝাবুঝি এবং গ্লোবাল মিটেক্স আরও বেশি more

গ্লোবাল মিউটেক্সগুলি তৈরি করার সময় কী কী ভাল, নিরাপদ নিদর্শন ব্যবহার করা যায়?

এক যে কাজ করবে

  • লোকাল নির্বিশেষে আমার মেশিনটি
  • মিটেক্সকে সঠিকভাবে প্রকাশের গ্যারান্টিযুক্ত
  • নিঃশব্দটি অর্জিত না হলে ptionচ্ছিকভাবে চিরকাল ঝুলবে না
  • অন্যান্য প্রক্রিয়াগুলি মিটেক্সকে ত্যাগ করে এমন ক্ষেত্রে ডিল করে

উত্তর:


402

আমি নিশ্চিত হয়ে উঠতে চাই যে এটি এখানে আছে, কারণ এটি সঠিকভাবে পাওয়া খুব কঠিন:

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();
        }
    }
}

1
আপনি usingচেক করতে createdNewএবং mutex.Dispose()ভিতরে যুক্ত করতে বাদ দিতে পারেন finally। আমি এখনই এটি স্পষ্টভাবে ব্যাখ্যা করতে পারি না (কারণটি আমি জানি না) তবে হয়ে ওঠার পরে mutex.WaitOneফিরে এসে নিজেকে এমন পরিস্থিতিতে ফেলেছি (আমি বর্তমানের মধ্যে মিউটেক্সটি অর্জন করেছি এবং তার পরে একটি নতুন কোড লোড করেছি এবং সেখান থেকে একই কোড কার্যকর করা হয়েছে) এটার মধ্যে). truecreatedNewfalseAppDomainAppDomain
সের্গেই.কুইক্সোটিক্যাক্সিস.আইভানভ

1. exitContext = falseকিছু আছে mutex.WaitOne(5000, false)? দেখে মনে হচ্ছে এটি শুধুমাত্র CoreCLR একটি জাহির সৃষ্টি করতে পারে , কারও হতাশ পারেন, 2. Mutexএর কন্সট্রাকটর, কারণ initiallyOwnedহয় falseআংশিকভাবে দ্বারা ব্যাখ্যা করা হয় এই দুটিই MSDN নিবন্ধ
জুন

3
একটি টিপ: এএসপি.এনইটি দিয়ে মুটেক্স ব্যবহার করে নজর রাখুন: "মুটেক্স শ্রেণি থ্রেড পরিচয় প্রয়োগ করে, তাই কোনও মুটেক্স কেবল এটি প্রাপ্ত থ্রেড দ্বারা প্রকাশ করা যেতে পারে contrast বিপরীতে, সেমফোর শ্রেণি থ্রেড পরিচয় প্রয়োগ করে না"। একটি ASP.NET অনুরোধ একাধিক থ্রেড দ্বারা পরিবেশন করা যেতে পারে।
স্যাম রুয়েবি

VB.NET- এ নিরাপদে স্টার্টআপস্টাইনস্ট্যান্স ইভেন্ট? সি # ডকস.মাইক্রোসফ্ট.কম
es-

ওয়েটঅন ব্যবহার না করে আমার উত্তরটি দেখুন। stackoverflow.com/a/59079638/4491768
ওয়াউটার

129

গৃহীত উত্তরটি ব্যবহার করে আমি একটি সহায়ক শ্রেণি তৈরি করেছি যাতে আপনি এটি লক বিবৃতিটি একইভাবে ব্যবহার করতে পারেন। ভেবেছিলাম ভাগ করে নেব।

ব্যবহার করুন:

using (new SingleGlobalInstance(1000)) //1000ms timeout on global lock
{
    //Only 1 of these runs at a time
    RunSomeStuff();
}

এবং সহায়ক শ্রেণি:

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();
        }
    }
}

দুর্দান্ত কাজ, ধন্যবাদ! এফওয়াইআই: কোড বিশ্লেষণের সময় CA2213 সতর্কতা রোধ করতে আমি উপরের ডিসপোজ পদ্ধতি আপডেট করেছি। বাকীগুলি জরিমানা পাস। আরও বিশদে বিশদ জন্য এমএসডিএন.মাইক্রোসফট.কোয়ারী
প্যাট হার্মেনস

1
সিঙ্গেলব্লালআইনস্ট্যান্স গ্রহণকারী ক্লাসে আমি কীভাবে টাইমআউট ব্যতিক্রম পরিচালনা করব। এছাড়াও কোনও উদাহরণ নির্মাণের সময় ব্যতিক্রম ছুঁড়ে ফেলা ভাল?
কিরণ

3
0 এর টাইমআউটটি এখনও শূন্যের টাইমআউট হওয়া উচিত, অনন্ত নয়! < 0পরিবর্তে জন্য ভাল চেক <= 0
ygoe

2
@ অ্যান্টিস্টার: আমি দেখতে পেয়েছি যে ডিসপোজ পদ্ধতিটির _mutex.Close()পরিবর্তে ব্যবহার করা _mutex.Dispose()আমার পক্ষে কাজ করে। অন্তর্নিহিত ওয়েটহ্যান্ডলটি নিষ্পত্তি করার চেষ্টা করে ত্রুটি হয়েছিল। Mutex.Close()অন্তর্নিহিত সংস্থানগুলি নিষ্পত্তি করে।
djpMusic

1
এটি দেখায় "অ্যাপনাম কাজ করা বন্ধ করে দিয়েছে।" যখন আমি অ্যাপ্লিকেশনটির দ্বিতীয় উদাহরণটি খোলার চেষ্টা করি। যখন ব্যবহারকারী অ্যাপটির দ্বিতীয় উদাহরণটি খোলার চেষ্টা করে আমি অ্যাপটিতে ফোকাস সেট করতে চাই। আমি এটা কিভাবে করবো?
ভাস্কর

13

গ্রহণযোগ্য উত্তরে একটি প্রতিযোগিতার শর্ত রয়েছে যখন 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();
        }
    }
}

8
নোট করুন এই সমস্যাটি এখন গৃহীত উত্তরে স্থির হয়েছে।
ভ্যান এনগুইন

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();
        }
    }
}

10

Mutex বা WinApi CreateMutex () কেউই আমার পক্ষে কাজ করে না।

একটি বিকল্প সমাধান:

static class Program
{
    [STAThread]
    static void Main()
    {
        if (SingleApplicationDetector.IsRunning()) {
            return;
        }

        Application.Run(new MainForm());

        SingleApplicationDetector.Close();
    }
}

এবং 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;
}

মুটেক্সের পরিবর্তে সেমফোর ব্যবহারের কারণ:

মুটেক্স শ্রেণি থ্রেড পরিচয় প্রয়োগ করে, তাই কোনও মুটেক্স কেবলমাত্র এটিই থ্রেড দ্বারা প্রকাশিত হতে পারে। বিপরীতে, Semaphore বর্গ থ্রেড পরিচয় প্রয়োগ করে না।

<< সিস্টেম.ট্রেডিং.মুটেক্স

রেফারেন্স: সেম্যাফোর.অপেনএক্সিং ()


7
Semaphore.OpenExistingএবং মধ্যে সম্ভাব্য জাতি শর্ত new Semaphore
xmedeko

3

কখনও কখনও উদাহরণস্বরূপ শেখা সর্বাধিক সহায়তা করে। তিনটি ভিন্ন কনসোল উইন্ডোতে এই কনসোল অ্যাপ্লিকেশনটি চালান। আপনি দেখতে পাবেন যে আপনি প্রথমে যে অ্যাপ্লিকেশনটি চালিয়েছেন তা প্রথমে মিউটেক্সটি অর্জন করে, যখন অন্য দু'জন তাদের পরিবর্তনের জন্য অপেক্ষা করছেন। তারপরে প্রথম অ্যাপ্লিকেশনটিতে এন্টার টিপুন, আপনি দেখতে পাবেন যে অ্যাপ্লিকেশন 2 এখন মুটেক্স অর্জন করে চলতে থাকবে, তবে অ্যাপ্লিকেশন 3 তার পরিবর্তনের জন্য অপেক্ষা করছে। আপনি অ্যাপ্লিকেশন 2 এন্টার চাপুন পরে আপনি দেখতে পাবেন যে অ্যাপ্লিকেশন 3 অব্যাহত রয়েছে। এটি উদাহরণস্বরূপ কোনও ফাইলকে লেখার মতো কেবল একটি থ্রেড (এই ক্ষেত্রে একটি প্রক্রিয়া) দ্বারা চালিত হওয়া কোডের একটি বিভাগকে সুরক্ষিত করার জন্য একটি মুটেক্সের ধারণাটি চিত্রিত করে।

using System;
using System.Threading;

namespace MutexExample
{
    class Program
    {
        static Mutex m = new Mutex(false, "myMutex");//create a new NAMED mutex, DO NOT OWN IT
        static void Main(string[] args)
        {
            Console.WriteLine("Waiting to acquire Mutex");
            m.WaitOne(); //ask to own the mutex, you'll be queued until it is released
            Console.WriteLine("Mutex acquired.\nPress enter to release Mutex");
            Console.ReadLine();
            m.ReleaseMutex();//release the mutex so other processes can use it
        }
    }
}

এখানে চিত্র বর্ণনা লিখুন


0

গ্লোবাল মুটেক্স কেবলমাত্র একটি অ্যাপ্লিকেশনটির কেবলমাত্র একটি উদাহরণ রয়েছে তা নিশ্চিত করার জন্য নয়। আমি ব্যক্তিগতভাবে মাইক্রোসফ্ট ব্যবহার করতে পছন্দ করি 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
    }
}

0

ওয়েটওন ছাড়াই একটি সমাধান (ডাব্লুপিএফের জন্য) কারণ এটি একটি পরিত্যক্ত মিউটেক্সএক্সেপশন তৈরি করতে পারে। এই সমাধানটি মুটেক্স কন্সট্রাক্টর ব্যবহার করে যা তৈরি করা নতুন বুলিয়ানকে ফেরত দেয় কিনা তা পরীক্ষা করে নিঃশব্দ ইতিমধ্যে তৈরি হয়েছে। এটি গেটটাইপ ()ও ব্যবহার করে G জিইউডি তাই কোনও এক্সিকিউটেবলের নামকরণ একাধিক উদাহরণের অনুমতি দেয় না।

গ্লোবাল বনাম স্থানীয় মুটেক্স নোট এতে দেখুন: https://docs.microsoft.com/en-us/dotnet/api/system.threading.mutex?view=netframework-4.8

private Mutex mutex;
private bool mutexCreated;

public App()
{
    string mutexId = $"Global\\{GetType().GUID}";
    mutex = new Mutex(true, mutexId, out mutexCreated);
}

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);
    if (!mutexCreated)
    {
        MessageBox.Show("Already started!");
        Shutdown();
    }
}

যেহেতু মুটেক্স আইডিপোজেবল কার্যকর করে এটি স্বয়ংক্রিয়ভাবে প্রকাশিত হয় তবে সম্পূর্ণ কল ডিসপোজ করার জন্য:

protected override void OnExit(ExitEventArgs e)
{
    base.OnExit(e);
    mutex.Dispose();
}

সবকিছুকে একটি বেস শ্রেণিতে স্থানান্তরিত করুন এবং গৃহীত উত্তর থেকে অনুমতিপ্রাপ্ত প্রত্যেকটি রুল যুক্ত করুন। এটি রিলিজমিউটেক্স যুক্ত করেছে যদিও এটি সত্যই প্রয়োজন বলে মনে হচ্ছে না কারণ এটি ওএস দ্বারা স্বয়ংক্রিয়ভাবে প্রকাশিত হয় (যদি অ্যাপ্লিকেশনটি ক্র্যাশ হয়ে যায় এবং রিলিজমুটেক্সকে কখনও কল না করে আপনি কি পুনরায় বুট করতে হবে?)

public class SingleApplication : Application
{
    private Mutex mutex;
    private bool mutexCreated;

    public SingleApplication()
    {
        string mutexId = $"Global\\{GetType().GUID}";

        MutexAccessRule allowEveryoneRule = new MutexAccessRule(
            new SecurityIdentifier(WellKnownSidType.WorldSid, null),
            MutexRights.FullControl, 
            AccessControlType.Allow);
        MutexSecurity securitySettings = new MutexSecurity();
        securitySettings.AddAccessRule(allowEveryoneRule);

        // initiallyOwned: true == false + mutex.WaitOne()
        mutex = new Mutex(initiallyOwned: true, mutexId, out mutexCreated, securitySettings);        }

    protected override void OnExit(ExitEventArgs e)
    {
        base.OnExit(e);
        if (mutexCreated)
        {
            try
            {
                mutex.ReleaseMutex();
            }
            catch (ApplicationException ex)
            {
                MessageBox.Show(ex.Message, ex.GetType().FullName, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        mutex.Dispose();
    }

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        if (!mutexCreated)
        {
            MessageBox.Show("Already started!");
            Shutdown();
        }
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.