c# - एक ही प्रोग्राम के कई उदाहरणों को सुरक्षित रखने से रोकने के लिए एक म्यूटेक्स का उपयोग कर रहा है?




winforms mutex (7)

मैं अपने प्रोग्राम के दूसरे उदाहरण को एक ही समय में चलने से रोकने के लिए इस कोड का उपयोग कर रहा हूं, क्या यह सुरक्षित है?

Mutex appSingleton = new System.Threading.Mutex(false, "MyAppSingleInstnceMutx");
if (appSingleton.WaitOne(0, false)) {
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new MainForm());
    appSingleton.Close();
} else {
    MessageBox.Show("Sorry, only one instance of MyApp is allowed.");
}

मुझे चिंता है कि अगर कुछ अपवाद फेंकता है और ऐप दुर्घटनाग्रस्त हो जाता है कि म्यूटेक्स अभी भी आयोजित किया जाएगा। क्या यह सच है?

https://code.i-harness.com


AbandonedMutexException से बचने के साथ टाइमआउट और सुरक्षा सेटिंग्स के साथ ऐप का उपयोग करें। मैंने अपनी कस्टम कक्षा का इस्तेमाल किया:

private class SingleAppMutexControl : IDisposable
    {
        private readonly Mutex _mutex;
        private readonly bool _hasHandle;

        public SingleAppMutexControl(string appGuid, int waitmillisecondsTimeout = 5000)
        {
            bool createdNew;
            var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null),
                MutexRights.FullControl, AccessControlType.Allow);
            var securitySettings = new MutexSecurity();
            securitySettings.AddAccessRule(allowEveryoneRule);
            _mutex = new Mutex(false, "Global\\" + appGuid, out createdNew, securitySettings);
            _hasHandle = false;
            try
            {
                _hasHandle = _mutex.WaitOne(waitmillisecondsTimeout, false);
                if (_hasHandle == false)
                    throw new System.TimeoutException();
            }
            catch (AbandonedMutexException)
            {
                _hasHandle = true;
            }
        }

        public void Dispose()
        {
            if (_mutex != null)
            {
                if (_hasHandle)
                    _mutex.ReleaseMutex();
                _mutex.Dispose();
            }
        }
    }

और इसका इस्तेमाल करें:

    private static void Main(string[] args)
    {
        try
        {
            const string appguid = "{xxxxxxxx-xxxxxxxx}";
            using (new SingleAppMutexControl(appguid))
            {
                //run main app
                Console.ReadLine();
            }
        }
        catch (System.TimeoutException)
        {
            Log.Warn("Application already runned");
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Fatal Error on running");
        }
    }

आप एक म्यूटेक्स का उपयोग कर सकते हैं, लेकिन पहले यह सुनिश्चित कर लें कि यह वास्तव में आप चाहते हैं।

क्योंकि "कई उदाहरणों से परहेज" स्पष्ट रूप से परिभाषित नहीं किया गया है। इसका मतलब हो सकता है

  1. एक ही उपयोगकर्ता सत्र में कई उदाहरणों से बचने से बचें, इससे कोई फर्क नहीं पड़ता कि उपयोगकर्ता सत्र में कितने डेस्कटॉप हैं, लेकिन कई उदाहरणों के लिए कई उदाहरणों को एक साथ चलाने की इजाजत दी गई है।
  2. एक ही डेस्कटॉप में कई उदाहरणों से बचने से बचें, लेकिन कई उदाहरणों को तब तक चलने की इजाजत दी जा सकती है जब तक कि प्रत्येक एक अलग डेस्कटॉप में न हो।
  3. एक ही उपयोगकर्ता खाते के लिए कई उदाहरणों से बचने से बचें, इससे कोई फर्क नहीं पड़ता कि इस खाते के तहत कितने डेस्कटॉप या सत्र चल रहे हैं, लेकिन एक अलग उपयोगकर्ता खाते के तहत चल रहे सत्रों के लिए कई उदाहरणों को एक साथ चलाने की इजाजत है।
  4. एक ही मशीन पर कई उदाहरणों से बचें। इसका मतलब यह है कि इससे कोई फर्क नहीं पड़ता कि उपयोगकर्ताओं की मनमानी संख्या से कितने डेस्कटॉप उपयोग किए जाते हैं, प्रोग्राम चलाने के सबसे अधिक उदाहरण हो सकते हैं।

एक म्यूटेक्स का उपयोग करके, आप मूल रूप से परिभाषित संख्या 4 का उपयोग कर रहे हैं।


कोड स्निपेट यहाँ है

public enum ApplicationSingleInstanceMode
{
    CurrentUserSession,
    AllSessionsOfCurrentUser,
    Pc
}

public class ApplicationSingleInstancePerUser: IDisposable
{
    private readonly EventWaitHandle _event;

    /// <summary>
    /// Shows if the current instance of ghost is the first
    /// </summary>
    public bool FirstInstance { get; private set; }

    /// <summary>
    /// Initializes 
    /// </summary>
    /// <param name="applicationName">The application name</param>
    /// <param name="mode">The single mode</param>
    public ApplicationSingleInstancePerUser(string applicationName, ApplicationSingleInstanceMode mode = ApplicationSingleInstanceMode.CurrentUserSession)
    {
        string name;
        if (mode == ApplicationSingleInstanceMode.CurrentUserSession)
            name = $"Local\\{applicationName}";
        else if (mode == ApplicationSingleInstanceMode.AllSessionsOfCurrentUser)
            name = $"Global\\{applicationName}{Environment.UserDomainName}";
        else
            name = $"Global\\{applicationName}";

        try
        {
            bool created;
            _event = new EventWaitHandle(false, EventResetMode.ManualReset, name, out created);
            FirstInstance = created;
        }
        catch
        {
        }
    }

    public void Dispose()
    {
        _event.Dispose();
    }
}

मैं इस विधि का उपयोग करता हूं, मेरा मानना ​​है कि यह सुरक्षित होना चाहिए क्योंकि म्यूटेक्स को नष्ट कर दिया जाता है यदि किसी भी एप्लिकेशन द्वारा लंबे समय तक नहीं रखा जाता है (और अनुप्रयोगों को समाप्त कर दिया जाता है यदि वे प्रारंभ में म्यूटक्स्ट नहीं बना सकते हैं)। यह 'AppDomain-process' में समान रूप से काम कर सकता है या नहीं (नीचे लिंक देखें):

// Make sure that appMutex has the lifetime of the code to guard --
// you must keep it from being collected (and the finalizer called, which
// will release the mutex, which is not good here!).
// You can also poke the mutex later.
Mutex appMutex;

// In some startup/initialization code
bool createdNew;
appMutex = new Mutex(true, "mutexname", out createdNew);
if (!createdNew) {
  // The mutex already existed - exit application.
  // Windows will release the resources for the process and the
  // mutex will go away when no process has it open.
  // Processes are much more cleaned-up after than threads :)
} else {
  // win \o/
}

ऊपर दिए गए दुर्भावनापूर्ण प्रोग्रामों के बारे में अन्य उत्तरों / टिप्पणियों में नोट्स से उपरोक्त है जो म्यूटेक्स पर बैठने में सक्षम हैं। यहां कोई चिंता नहीं है। इसके अलावा, "स्थानीय" स्थान में बनाया गया अपरिवर्तित म्यूटेक्स। यह शायद यहां सही बात है।

देखें: http://ayende.com/Blog/archive/2008/02/28/The-mysterious-life-of-mutexes.aspx - जॉन स्कीट के साथ आता है ;-)


यहां बताया गया है कि मैंने इसका कैसे संपर्क किया है

प्रोग्राम क्लास में: 1. System.Diagnostics. Process.GetCurrentProcess () का उपयोग कर अपने एप्लिकेशन का प्रोसेस प्राप्त करें 2. Process.GetProcessesByName (thisProcess.ProcessName) का उपयोग कर अपने एप्लिकेशन के वर्तमान नाम के साथ खुली प्रक्रियाओं के संग्रह के माध्यम से चरण 3। प्रत्येक प्रक्रिया की जांच करें। इस प्रोसेस के खिलाफ आईडी.आईडी और यदि कोई उदाहरण पहले ही खोला गया है तो कम से कम 1 नाम से मेल खाता है लेकिन आईडी नहीं, अन्यथा ओपनिंग इंस्टेंस जारी रखें

using System.Diagnostics;

.....    

static void Main()
{
   Process thisProcess = Process.GetCurrentProcess();
   foreach(Process p in Process.GetProcessesByName(thisProcess.ProcessName))
   {
      if(p.Id != thisProcess.Id)
      {
         // Do whatever u want here to alert user to multiple instance
         return;
      }
   }
   // Continue on with opening application

इसे समाप्त करने के लिए एक अच्छा स्पर्श उपयोगकर्ता को पहले से ही खोला गया उदाहरण प्रस्तुत करना होगा, संभावना है कि उन्हें नहीं पता था कि यह खुला था, इसलिए चलिए उन्हें दिखाएं। ऐसा करने के लिए मैं Windows मैसेजिंग लूप, एक कस्टम संदेश में एक संदेश प्रसारित करने के लिए User32.dll का उपयोग करता हूं, और मेरे पास ऐप WNDProc विधि में इसके लिए सुनता है, और यदि यह संदेश मिलता है, तो यह स्वयं को उपयोगकर्ता, फॉर्म में प्रस्तुत करता है .Show () या क्या नहीं


विंडोज़ पर, प्रक्रिया को समाप्त करने के निम्नलिखित परिणाम हैं:

  • प्रक्रिया में किसी भी शेष धागे को समाप्त करने के लिए चिह्नित किया जाता है।
  • प्रक्रिया द्वारा आवंटित कोई भी संसाधन मुक्त कर दिया गया है।
  • सभी कर्नेल ऑब्जेक्ट बंद हैं।
  • प्रक्रिया कोड स्मृति से हटा दिया गया है।
  • प्रक्रिया निकास कोड सेट है।
  • प्रक्रिया वस्तु संकेतित है।

म्यूटेक्स ऑब्जेक्ट्स कर्नेल ऑब्जेक्ट्स हैं, इसलिए प्रक्रिया समाप्त होने पर किसी भी प्रक्रिया द्वारा आयोजित की जाती है (विंडोज़ में वैसे भी)।

लेकिन, CreateMutex () दस्तावेज़ों से निम्न बिट को नोट करें:

यदि आप अपने एप्लिकेशन को एक ही उदाहरण में सीमित करने के लिए नामित म्यूटेक्स का उपयोग कर रहे हैं, तो एक दुर्भावनापूर्ण उपयोगकर्ता आपके म्यूटेक्स को आपके द्वारा शुरू करने से पहले और आपके एप्लिकेशन को शुरू होने से रोक सकता है।


हां, यह सुरक्षित है, मैं निम्नलिखित पैटर्न का सुझाव दूंगा, क्योंकि आपको यह सुनिश्चित करने की ज़रूरत है कि Mutex हमेशा जारी हो जाए।

using( Mutex mutex = new Mutex( false, "mutex name" ) )
{
    if( !mutex.WaitOne( 0, true ) )
    {
        MessageBox.Show("Unable to run multiple instances of this program.",
                        "Error",  
                        MessageBoxButtons.OK, 
                        MessageBoxIcon.Error);
    }
    else
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm());                  
    }
}




single-instance