2009-06-07 12 views
12

यह क्या है और इसका उपयोग कैसे करें?क्या कोई सिंक्रनाइज़ेशन क्लास है जो सी # में फीफो ऑर्डर की गारंटी देती है?

मुझे इसकी आवश्यकता है क्योंकि मेरे पास एक टाइमर है जो हर सेकेंड में डीबी में प्रवेश करता है, और मेरे पास टाइमर हैंडलर और मुख्य थ्रेड के बीच एक साझा संसाधन है। मैं यह जानना चाहता हूं कि अगर टाइमर हैंडलर सम्मिलन में एक से अधिक सेकंड लेता है तो प्रतीक्षा किए गए थ्रेड को क्रम में निष्पादित किया जाना चाहिए। यह मेरी घड़ी हैंडलर

private void InsertBasicVaraibles(object param) 
{ 
      try 
      { 
       DataTablesMutex.WaitOne();//mutex for my shared resources 
       //insert into DB 
      } 
      catch (Exception ex) 
      { 
       //Handle 
      } 
      finally 
      { 
       DataTablesMutex.ReleaseMutex(); 
      } 
} 

के लिए एक नमूना कोड है लेकिन वर्तमान में म्युटेक्स किसी भी क्रम गारंटी नहीं है। विस्तृत प्रश्न डालने के बाद जवाब नहीं है !!!

+0

परिभाषा के द्वारा एक ताला फीफो है:

reentrancy मुद्दे पर जैसा कि मैंने यह करने के लिए कोड को संशोधित किया। एक धागा अंदर जाता है, और जब तक यह बाहर नहीं जाता है तब तक कोई और नहीं हो जाता है! –

+10

@ मिच: लेकिन इस बात की कोई गारंटी नहीं है कि पहले धागे को इंतजार करना था जो तुरंत बाद में अनब्लॉक हो जाता है। तो नहीं, ताले फीफो नहीं हैं। –

+2

(यानी यदि टी 1 वर्तमान में लॉक रखता है, तो टी 2 इसे हासिल करने का प्रयास करता है, तो टी 3 इसे हासिल करने का प्रयास करता है, टी 3 के पहले टी 3 इसे प्राप्त करने की कोई गारंटी नहीं है।) –

उत्तर

26

आप यह करने के लिए अपने स्वयं के वर्ग में लिखने के लिए की आवश्यकता होगी, मैं इस उदाहरण पाया (चिपकाया है क्योंकि यह के रूप में यद्यपि साइट के डोमेन अवधि बीत चुकी है दिखता है):

using System.Threading; 

public sealed class QueuedLock 
{ 
    private object innerLock; 
    private volatile int ticketsCount = 0; 
    private volatile int ticketToRide = 1; 

    public QueuedLock() 
    { 
     innerLock = new Object(); 
    } 

    public void Enter() 
    { 
     int myTicket = Interlocked.Increment(ref ticketsCount); 
     Monitor.Enter(innerLock); 
     while (true) 
     { 

      if (myTicket == ticketToRide) 
      { 
       return; 
      } 
      else 
      { 
       Monitor.Wait(innerLock); 
      } 
     } 
    } 

    public void Exit() 
    { 
     Interlocked.Increment(ref ticketToRide); 
     Monitor.PulseAll(innerLock); 
     Monitor.Exit(innerLock); 
    } 
} 

उपयोग के उदाहरण:

QueuedLock queuedLock = new QueuedLock(); 

try 
{ 
    queuedLock.Enter(); 
    // here code which needs to be synchronized 
    // in correct order 
} 
finally 
{ 
    queuedLock.Exit(); 
} 

Source via Google cache

+4

यह क्विकर लॉक आईडीस्पोज़ेबल –

+0

रेफरी द्वारा अस्थिरता को पार करने के लिए आजकल सी # कंपाइलर द्वारा प्रोत्साहित नहीं किया गया है, यह चेतावनी देता है कि यह नहीं होगा अस्थिर के रूप में माना जाता है। इसके अलावा मेरी आज की समस्या का एकदम सही समाधान! – AlexanderVX

+0

पूरी तरह से काम किया! – merger

1

वहाँ पर कोई गारंटी क्रम है किसी भी निर्मित तुल्यकालन वस्तुओं: http://msdn.microsoft.com/en-us/library/ms684266(VS.85).aspx

आप एक गारंटीकृत आपको हालांकि यह रूप में आसान नहीं है कि के रूप में यह ध्वनि हो सकता है कोशिश करते हैं और कुछ अपने आप का निर्माण करने के, ध्यान दें होगा चाहते हैं , विशेष रूप से जब एकाधिक धागे एक ही समय में (करीब) सिंक्रनाइज़ेशन बिंदु तक पहुंचते हैं। कुछ हद तक वे जारी किए जाने वाले आदेश हमेशा 'यादृच्छिक' होंगे क्योंकि आप अनुमान लगा सकते हैं कि बिंदु किस क्रम में पहुंचा है, तो क्या इससे वाकई कोई फर्क पड़ता है?

+0

लिंक ओएस प्राइमेटिव्स के बारे में निश्चित रूप से है ... किसी बिंदु पर .NET वाले इनके शीर्ष पर बनाए जाएंगे, इसलिए मुझे लगता है कि इसका मतलब है कि फीफो की गारंटी नहीं दी जा सकती है ... जॉन का जवाब भी देखें। – jerryjvl

+1

समस्या आमतौर पर लॉक में यादृच्छिक क्रम में प्रवेश करने वाले थ्रेड के साथ नहीं होती है जब वे सभी एक ही समय में लॉक को पकड़ने का प्रयास करते हैं। समस्या तब उत्पन्न होती है जब थ्रेड जो लंबे समय तक लॉक में प्रवेश करने का इंतजार कर रहे थे, वे बाद में लॉक में प्रवेश करने की कोशिश वाले धागे से लाइन में कट जाते हैं। एक व्यस्त वेब सर्वर की कल्पना करें जहां 1000 अनुरोध लगातार साझा संसाधन तक पहुंचने का प्रयास कर रहे हैं, और लॉक पर प्रतीक्षा करने के लिए पहला धागा इंतजार कर रहा है क्योंकि बाद के अनुरोध उनकी बारी से आगे ताला चोरी करते रहते हैं। –

10

बस जो डफी के "विंडोज़ पर समवर्ती प्रोग्रामिंग" पढ़ना ऐसा लगता है जैसे आप आमतौर पर .NET मॉनीटर से फीफो व्यवहार प्राप्त करेंगे, लेकिन ऐसी कुछ स्थितियां हैं जहां ऐसा नहीं होगा।

पुस्तक का पृष्ठ 273 कहता है: "क्योंकि मॉनीटर आंतरिक रूप से कर्नेल ऑब्जेक्ट्स का उपयोग करते हैं, इसलिए वे वही मोटे तौर पर-फीफो व्यवहार प्रदर्शित करते हैं जो ओएस सिंक्रनाइज़ेशन तंत्र भी प्रदर्शित करता है (पिछले अध्याय में वर्णित)। मॉनीटर अनुचित हैं, इसलिए यदि कोई अन्य धागा एक जागृत प्रतीक्षा धागा लॉक प्राप्त करने की कोशिश करने से पहले लॉक में घुसपैठ और अधिग्रहण करता है, स्नीकी थ्रेड को लॉक प्राप्त करने की अनुमति है। "

मैं तुरंत अनुभाग संदर्भित "पिछले अध्याय में" नहीं मिल सकता है लेकिन यह ध्यान दें कि ताले scalability में सुधार लाने और ताला काफिलों कम करने के लिए विंडोज के हाल के संस्करणों में जान-बूझकर अनुचित बनाया गया है है।

क्या आपको निश्चित रूप से फीफो होने के लिए अपने लॉक की आवश्यकता है? शायद समस्या से निपटने के लिए एक अलग तरीका है। मुझे .NET में किसी भी ताले के बारे में पता नहीं है जिसे फीफो होने की गारंटी है।

+0

जॉन स्कीट सामान्य, सही है - Win2k3 SP2 (ish?) और ऊपर 100% उचित लॉकिंग नहीं है, और यह जानबूझकर है। –

+4

-1: कोई असली समाधान प्रदान नहीं किया गया – Svisstack

+0

वास्तव में मजेदार क्या है जब "स्नीकी थ्रेड" भी होता है जो मॉनीटर को छोड़ देता है। और, इस प्रकार, यह एक लूप में हमेशा के लिए जारी रहता है, दूसरे धागे को भूख से बाहर कर देता है। सीई 5 पर नेट कॉम्पैक्ट फ्रेमवर्क में बस कुछ पुराने कोड के साथ इस व्यवहार में भाग गया। – reirab

7

आप अपने सिस्टम को फिर से डिजाइन धागे के निष्पादन के आदेश पर भरोसा नहीं करना चाहिए। उदाहरण के लिए, अपने धागे को एक डीबी कॉल करने के बजाए जो एक से अधिक सेकंड ले सकता है, अपने धागे को एक कमान जैसी डेटा संरचना में निष्पादित करने के आदेश को रखें (या यदि कोई ऐसा कहता है तो एक ढेर "यह कहता है एक और से पहले हो ")। फिर, खाली समय में, कतार को निकालें और उचित समय में एक बार अपने डीबी सम्मिलित करें।

1

असल में जवाब अच्छे हैं, लेकिन मैं पृष्ठभूमि धागा में इस प्रकार

private void InsertBasicVaraibles() 
    { 
     int functionStopwatch = 0; 
     while(true) 
     { 

      try 
      { 
      functionStopwatch = Environment.TickCount; 
      DataTablesMutex.WaitOne();//mutex for my shared resources 
      //insert into DB 
      } 
      catch (Exception ex) 
      { 
      //Handle    
      } 
      finally    
      {     
       DataTablesMutex.ReleaseMutex(); 
      } 

      //simulate the timer tick value 
      functionStopwatch = Environment.TickCount - functionStopwatch; 
      int diff = INSERTION_PERIOD - functionStopwatch; 
      int sleep = diff >= 0 ? diff:0; 
      Thread.Sleep(sleep); 
     } 
    } 
+0

सुंदर नींद तर्क! अब मेरे सभी कोड को फिर से लिखना :) – divinci

0

मैथ्यू Brindley के जवाब पर अनुवर्ती कार्रवाई टाइमर को हटाने के द्वारा समस्या का समाधान और विधि (टाइमर हैंडलर पहले) चलाते हैं।

हैं से

lock (LocalConnection.locker) {...} 

कोड परिवर्तित तो आप या तो एक IDisposable करते हैं या कर सकता है मैं क्या किया:

public static void Locking(Action action) { 
    Lock(); 
    try { 
    action(); 
    } finally { 
    Unlock(); 
    } 
} 

LocalConnection.Locking(() => {...}); 

मैं IDisposable के खिलाफ फैसला किया है, क्योंकि यह हर कॉल पर एक नया अदृश्य वस्तु बनाता हैं ।

public sealed class QueuedLock { 
    private object innerLock = new object(); 
    private volatile int ticketsCount = 0; 
    private volatile int ticketToRide = 1; 
    ThreadLocal<int> reenter = new ThreadLocal<int>(); 

    public void Enter() { 
     reenter.Value++; 
     if (reenter.Value > 1) 
      return; 
     int myTicket = Interlocked.Increment(ref ticketsCount); 
     Monitor.Enter(innerLock); 
     while (true) { 
      if (myTicket == ticketToRide) { 
       return; 
      } else { 
       Monitor.Wait(innerLock); 
      } 
     } 
    } 

    public void Exit() { 
     if (reenter.Value > 0) 
      reenter.Value--; 
     if (reenter.Value > 0) 
      return; 
     Interlocked.Increment(ref ticketToRide); 
     Monitor.PulseAll(innerLock); 
     Monitor.Exit(innerLock); 
    } 
} 
संबंधित मुद्दे

 संबंधित मुद्दे