2010-01-25 7 views
12

अक्सर, जब मैं एक वर्ग है जो धागे की सुरक्षित है चाहता हूँ, मैं निम्नलिखित की तरह कुछ कार्य करें:क्या यह सी # में थ्रेड-सेफ क्लासेस बनाने के लिए एक अच्छा डिजाइन है?

public class ThreadSafeClass 
{ 
    private readonly object theLock = new object(); 

    private double propertyA; 
    public double PropertyA 
    { 
     get 
     { 
      lock (theLock) 
      { 
       return propertyA; 
      } 
     } 
     set 
     { 
      lock (theLock) 
      { 
       propertyA = value; 
      } 
     } 
    } 

    private double propertyB; 
    public double PropertyB 
    { 
     get 
     { 
      lock (theLock) 
      { 
       return propertyB; 
      } 
     } 
     set 
     { 
      lock (theLock) 
      { 
       propertyB = value; 
      } 
     } 
    } 

    public void SomeMethod() 
    { 
     lock (theLock) 
     { 
      PropertyA = 2.0 * PropertyB; 
     } 
    } 
} 

यह काम करता है, लेकिन यह बहुत वर्बोज़ है। कभी-कभी मैं प्रत्येक विधि और संपत्ति के लिए एक लॉक ऑब्जेक्ट भी बना देता हूं जो अधिक verbosity और जटिलता बनाते हैं।

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

संपादित करें: जैसा कि कई उत्तरदाताओं ने जोर दिया है, वहां कोई "चांदी बुलेट" धागा-सुरक्षित वर्ग डिज़ाइन नहीं है। मैं बस यह समझने की कोशिश कर रहा हूं कि मैं जिस पैटर्न का उपयोग कर रहा हूं वह अच्छे समाधानों में से एक है। बेशक किसी विशेष स्थिति में सबसे अच्छा समाधान समस्या निर्भर है। नीचे दिए गए कई उत्तरों में वैकल्पिक डिज़ाइन शामिल हैं जिन्हें माना जाना चाहिए।

संपादित करें: इसके अलावा, थ्रेड सुरक्षा की एक से अधिक परिभाषाएं हैं। उदाहरण के लिए, ऊपर मेरी कार्यान्वयन में, निम्न कोड नहीं धागा सुरक्षित होगा:

var myObject = new ThreadSafeClass(); 
myObject.PropertyA++; // NOT thread-safe 

तो, ऊपर वर्ग परिभाषा एक अच्छा दृष्टिकोण का प्रतिनिधित्व करता है? यदि नहीं, तो आप समान व्यवहार वाले डिज़ाइन के लिए क्या अनुशंसा करेंगे जो उपयोग के समान सेट के लिए थ्रेड-सुरक्षित होगा?

+4

कृपया पहले खोजें: http://stackoverflow.com/search?q=What+is+the+Best+Practice+for+ क्रिएटिंग + थ्रेड- Safe+Classes+in+C%23 –

+0

एचएम। अपने कोड में, आप प्रॉपर्टीए और प्रॉपर्टीबी दोनों को पढ़ने के लिए एक ही लॉक ऑब्जेक्ट का उपयोग करते हैं। इसका मतलब है कि प्रॉपर्टीए पढ़ने वाला एक थ्रेड प्रॉपर्टीबी को पढ़ने की कोशिश कर रहा है जब तक कि पहला धागा पूरा न हो जाए। क्या तुम यही चाहते हो? अगर यह मेरी कक्षा थी, तो मैं प्रत्येक गेटर के लिए एक अलग पठन लॉकर बनाउंगा और फिर सेटर्स को उस लॉक का भी सम्मान करना होगा। नीचे एक उत्तर देखें। –

+0

मैंने अभी आपको नीचे गिरा दिया क्योंकि थ्रेड-सुरक्षित वर्ग बनाने का कोई भी तरीका नहीं है। इस प्रश्न का कोई भी जवाब भविष्य के पाठकों को गलत इंप्रेशन देने का जोखिम उठाता है। –

उत्तर

8

बहु-थ्रेडिंग समस्या के लिए कोई "एक-आकार-फिट-सब" समाधान नहीं है। अपरिवर्तनीय कक्षाएं बनाने और विभिन्न सिंक्रनाइज़ेशन प्राइमेटिव के बारे में कुछ शोध करने के लिए कुछ शोध करें।

यह एक अर्द्ध अपरिवर्तनीय या -प्रोग्रामर-अपरिवर्तनीय वर्ग का एक उदाहरण है।

public class ThreadSafeClass 
{ 
    public double A { get; private set; } 
    public double B { get; private set; } 
    public double C { get; private set; } 

    public ThreadSafeClass(double a, double b, double c) 
    { 
     A = a; 
     B = b; 
     C = c; 
    } 

    public ThreadSafeClass RecalculateA() 
    { 
     return new ThreadSafeClass(2.0 * B, B, C); 
    } 
} 

यह उदाहरण किसी अन्य वर्ग में अपने तुल्यकालन कोड ले जाता है और एक उदाहरण के लिए उपयोग serializes।हकीकत में, आप वास्तव में किसी भी समय किसी ऑब्जेक्ट पर एक से अधिक थ्रेड ऑपरेटिंग नहीं करना चाहते हैं।

public class ThreadSafeClass 
{ 
    public double PropertyA { get; set; } 
    public double PropertyB { get; set; } 
    public double PropertyC { get; set; } 

    private ThreadSafeClass() 
    { 

    } 

    public void ModifyClass() 
    { 
     // do stuff 
    } 

    public class Synchronizer 
    { 
     private ThreadSafeClass instance = new ThreadSafeClass(); 
     private readonly object locker = new object(); 

     public void Execute(Action<ThreadSafeClass> action) 
     { 
      lock (locker) 
      { 
       action(instance); 
      } 
     } 

     public T Execute<T>(Func<ThreadSafeClass, T> func) 
     { 
      lock (locker) 
      { 
       return func(instance); 
      } 
     } 
    } 
} 

यहां एक त्वरित उदाहरण है कि आप इसका उपयोग कैसे करेंगे। यह थोड़ा गुंजाइश प्रतीत हो सकता है लेकिन यह आपको एक बार में उदाहरण पर कई कार्यों को निष्पादित करने की अनुमति देता है।

var syn = new ThreadSafeClass.Synchronizer(); 

syn.Execute(inst => { 
    inst.PropertyA = 2.0; 
    inst.PropertyB = 2.0; 
    inst.PropertyC = 2.0; 
}); 

var a = syn.Execute<double>(inst => { 
    return inst.PropertyA + inst.PropertyB; 
}); 
+0

मैं यहां आपका दृष्टिकोण समझता हूं - और मुझे लगता है कि कई मामलों में यह सबसे अच्छा होगा। हालांकि, यह ए, बी, और सी को संपत्ति सिंटैक्स के साथ बदलने की अनुमति नहीं देता है, और यदि अपडेट्स बहुत बार होते हैं तो अपडेट की समस्याएं उत्पन्न होती हैं क्योंकि प्रत्येक अपडेट में एक नई ऑब्जेक्ट बनाने और जीसी को पुराने को संभालने की अनुमति मिलती है। –

+0

इस तरह की कक्षा के लिए अच्छा नहीं है। लेकिन किसी भी प्रकार की व्यावसायिक वस्तु के लिए आप सही हैं। – ChaosPandion

+1

यह सिर्फ एक अपरिवर्तनीय वर्ग का एक उदाहरण है। हालांकि यह तकनीकी रूप से सही कहने के लिए सही है कि यह "थ्रेड सुरक्षित" है (इस अर्थ में कि एकाधिक एक साथ धागे के साथ बातचीत भ्रष्टाचार या दुर्व्यवहार का कारण नहीं बनती है) यह शायद ही एक मॉडल है "इस तरह सभी 'थ्रेड-सुरक्षित' वर्गों को" । –

3

ध्यान रखें कि "थ्रेड सुरक्षित" शब्द विशिष्ट नहीं है; आप यहां क्या कर रहे हैं Monitor लॉक के उपयोग के माध्यम से अधिक सटीक रूप से "सिंक्रनाइज़ेशन" के रूप में जाना जाएगा।

उस ने कहा, सिंक्रनाइज़ कोड के आसपास वर्बोजिटी काफी अपरिहार्य है।

lock (theLock) 
{ 
    propertyB = value; 
} 
इस में

:: आप इस तरह की बातें करके अपने उदाहरण में खाली स्थान के से कुछ में कटौती कर सकता है

lock (theLock) propertyB = value; 

या नहीं, यह आपके लिए सही दृष्टिकोण है के रूप में हम वास्तव में अधिक जानकारी की जरूरत है। सिंक्रनाइज़ेशन "थ्रेड सुरक्षा" के लिए सिर्फ एक दृष्टिकोण है; अपरिवर्तनीय वस्तुओं, semaphores, आदि सभी अलग-अलग तंत्र हैं जो विभिन्न उपयोग-मामलों के अनुरूप हैं। आपके द्वारा प्रदान किए जाने वाले सरल उदाहरण के लिए (जहां ऐसा लगता है कि आप प्राप्त करने या सेट ऑपरेशन की परमाणुता सुनिश्चित करने की कोशिश कर रहे हैं), तो ऐसा लगता है कि आपने सही चीजें की हैं, लेकिन यदि आपका कोड अधिक से अधिक होने का इरादा है एक उदाहरण से चित्रण तो चीजें उतनी सरल नहीं हो सकती हैं।

0

ऊपर मेरी टिप्पणी के अनुसार - यह एक छोटे hairier अगर आप एक साथ पाठकों की अनुमति दी, लेकिन केवल एक लेखक की अनुमति चाहते हो जाता है। नोट, यदि आपके पास .NET 3.5 है, तो इस प्रकार के पैटर्न के लिए ReaderWriterLock के बजाय ReaderWriterLockSlim का उपयोग करें।

public class ThreadSafeClass 
{ 
    private readonly ReaderWriterLock theLock = new ReaderWriterLock(); 

    private double propertyA; 
    public double PropertyA 
    { 
     get 
     { 
      theLock.AcquireReaderLock(Timeout.Infinite); 
      try 
      { 
       return propertyA; 
      } 
      finally 
      { 
       theLock.ReleaseReaderLock(); 
      } 
     } 
     set 
     { 
      theLock.AcquireWriterLock(Timeout.Infinite); 
      try 
      { 
       propertyA = value; 
      } 
      finally 
      { 
       theLock.ReleaseWriterLock(); 
      } 
     } 
    } 

    private double propertyB; 
    public double PropertyB 
    { 
     get 
     { 
      theLock.AcquireReaderLock(Timeout.Infinite); 
      try 
      { 
       return propertyB; 
      } 
      finally 
      { 
       theLock.ReleaseReaderLock(); 
      } 
     } 
     set 
     { 
      theLock.AcquireWriterLock(Timeout.Infinite); 
      try 
      { 
       propertyB = value; 
      } 
      finally 
      { 
       theLock.ReleaseWriterLock(); 
      } 
     } 
    } 

    public void SomeMethod() 
    { 
     theLock.AcquireWriterLock(Timeout.Infinite); 
     try 
     { 
      theLock.AcquireReaderLock(Timeout.Infinite); 
      try 
      { 
       PropertyA = 2.0 * PropertyB; 
      } 
      finally 
      { 
       theLock.ReleaseReaderLock(); 
      } 
     } 
     finally 
     { 
      theLock.ReleaseWriterLock(); 
     } 
    } 
} 
+0

क्या होगा यदि आपके पास दो की बजाय 10 गुण थे ?! –

+4

अपने टूल्स को जानें, इस प्रकार के लॉक को करने के लिए ढांचे में रीडरवाइटर लॉकस्लिम है: http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx –

+0

यही कारण है कि मैंने पूछा कि क्या आप चाहते हैं गुणों को पूरी तरह से एक साथ सिंक किया गया है या नहीं। यह सब आपकी जरूरतों पर आधारित है। आप जटिलता के लिए लचीलापन व्यापार करते हैं। रीडरवाइटर लॉकस्लिम (या रीडरवाइटर लॉक यदि आप हेवीवेट संस्करण चाहते हैं) के क्रिस का सुझाव लेखकों को क्रमबद्ध करने के लिए काम करेगा। –

1

आपको Interlocked कक्षा सहायक मिल सकती है। इसमें कई परमाणु संचालन शामिल हैं।

1

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

4

मुझे पता है कि यह एक स्मार्ट ** ** स्मार्ट की तरह लग सकता है लेकिन ... थ्रेडसेफ कक्षाओं को विकसित करने का सबसे अच्छा तरीका वास्तव में बहुसंख्यक के बारे में जानना है, इसके प्रभावों, इसकी जटिलताओं और इसका क्या अर्थ है। कोई रजत बुलेट नहीं है।

  • पहले you need a good reason to use it। थ्रेड एक उपकरण हैं, आप अपने नए पाए गए हथौड़ा के साथ सबकुछ हिट नहीं करना चाहते हैं।
  • दूसरे,, बहु सूत्रण की समस्याओं ... deadlocks, race conditions, starvation और पर इतना
  • तीसरा बारे में जानने यकीन है कि यह लायक है या नहीं। मैं लाभ/लागत के बारे में बात कर रहा हूं।
  • अंत में ... भारी डीबगिंग के लिए तैयार रहें। Debugging multithreaded code मानक पुराने अनुक्रमिक कोड से कहीं अधिक कठिन है। ऐसा करने के तरीके के बारे में कुछ तकनीक जानें।

गंभीरता से ... मल्टीथ्रेड (उत्पादन परिदृश्यों में मेरा मतलब है) तक प्रयास न करें जब तक कि आपको पता न हो कि आप स्वयं को क्या प्राप्त कर रहे हैं ... यह एक बड़ी गलती हो सकती है।

संपादित करें: आपको निश्चित रूप से ऑपरेटिंग सिस्टम और आपकी पसंद की भाषा दोनों के सिंक्रनाइज़ेशन प्राइमेटिव्स को जानना चाहिए (इस मामले में विंडोज के तहत सी #, मुझे लगता है)।

मुझे खेद है कि मैं केवल कक्षा थ्रेडसेफ बनाने के लिए कोड नहीं दे रहा हूं। ऐसा इसलिए है क्योंकि यह मौजूद नहीं है। एक पूरी तरह से थ्रेडसेफ वर्ग शायद थ्रेड से बचने की तुलना में धीमा हो जाएगा और शायद आप जो कुछ भी कर रहे हैं उस पर एक बाधा के रूप में कार्य करेंगे ... जो भी चीज आप थ्रेड का उपयोग कर प्राप्त कर रहे हैं उसे प्रभावी ढंग से पूर्ववत कर दें।

+0

मुझे पता है कि कोई चांदी की बुलेट नहीं है। मेरे ऊपर वर्णित पैटर्न का उपयोग करके मेरे पास बहुत सारे उत्पादन कोड हैं - और मैं आपसे सहमत हूं कि बहु-थ्रेडिंग को हल्के ढंग से नहीं लिया जाना चाहिए। हालांकि, मेरा आवेदन मजबूत है और वर्तमान में किसी भी deadlocks या दौड़ की स्थिति से पीड़ित नहीं है - हालांकि यह अतीत में है। मैं यह नहीं कह रहा हूं कि इस पैटर्न या भिन्नताएं सभी बहु-थ्रेडिंग समस्या का उत्तर हैं। मैं सिर्फ यह पूछ रहा हूं कि ऊपर दिए गए कोड के व्यवहार को पाने के लिए एक और शानदार तरीका है या नहीं। यह मेरे लिए आदर्श नहीं लग रहा था और मैं समुदाय की खुफिया जानकारी खींचने की कोशिश कर रहा हूं। –

+5

मुझे कहना है कि यह बहुत बुरी सलाह है। यह कहने जैसा है कि प्रत्येक को एक आंख उठा लेने से पहले एक मास्टर शिल्पकार बनना चाहिए। आपको कहीं से शुरू करना है, और यह एक बुरी जगह नहीं है। –

+0

मुझे इस पर जोनाथन से सहमत होना है। – ChaosPandion

3

चूंकि ऐसा कोई नहीं लगता है, तो यहां आपके विशिष्ट डिज़ाइन पर कुछ विश्लेषण है।

  • कोई भी संपत्ति पढ़ना चाहते हैं? थ्रेडसेफ
  • किसी भी संपत्ति को अपडेट करना चाहते हैं? थ्रेडसेफ
  • एक ही संपत्ति को पढ़ना चाहते हैं और फिर इसे अपने मूल मूल्य के आधार पर अपडेट करना चाहते हैं?थ्रेडसेफ

थ्रेड 2 थ्रेड 1 के पढ़ने और अपडेट के बीच मान को अपडेट कर सकता है।

  • एक ही समय में दो संबंधित गुणों को अपडेट करना चाहते हैं? थ्रेडसेफ

आप प्रॉपर्टी ए के साथ थ्रेड 1 का मान और संपत्ति बी के थ्रेड 2 के मान वाले हो सकते हैं।

  1. थ्रेड 1 अद्यतन एक
  2. थ्रेड 2 अद्यतन एक
  3. थ्रेड 1 अद्यतन बी
  4. थ्रेड 2 अद्यतन बी

    • ही समय में दो संबंधित गुणों पढ़ना चाहते हैं? नहीं threadsafe

फिर से, आप पहली और दूसरी पढ़ने के बीच बाधित हो सकता है।

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

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