2010-10-13 21 views
7

मैंने देखा कि बढ़ावा सेफफोर्स का समर्थन नहीं लगता है। समान प्रभाव प्राप्त करने का सबसे आसान तरीका क्या है?सी ++ में बूस्ट का उपयोग करके मैं सैमफोर के समान कुछ कैसे प्राप्त कर सकता हूं?

+0

क्या आप इस व्यवहार के बारे में अधिक विशिष्ट हो सकते हैं कि आप किस व्यवहार की तलाश में हैं? यह देखते हुए कि लोग लगभग 14 विभिन्न प्रकार के सेमफोरों के साथ आए हैं। – jalf

+0

अभी, कुछ ऐसा जो मुझे दे देगा, उदाहरण के लिए, भोजन करने वाले दार्शनिक की समस्या (5 दार्शनिकों के साथ) को अधिकतम 4 खाने वाले लोगों की संख्या सीमित करके हल करें। सेमफोरों के साथ, मैं केवल 4 का प्रारंभिक मान निर्धारित कर सकता हूं और प्रत्येक को दार्शनिक सैद्धांत और सिग्नल पर इंतजार करते हैं जब किया जाता है। – jonderry

उत्तर

6

आपको या तो Boost Interprocess semaphore या Boost Thread synchronization प्राइमेटिव की आवश्यकता है।

Mutex/Lock और condition प्राथमिकताएं हैं जिनका उपयोग आमतौर पर एक ही प्रक्रिया के एकाधिक धागे में साझा संसाधनों तक पहुंच को सिंक्रनाइज़ करने के लिए किया जाता है। exclusive, readers-writer और recursive/reentrant म्यूटेक्स के प्रकार हैं। म्यूटेक्स, दूसरे शब्दों में, एक विशेष लॉक है। जब आप mutex को अनलॉक करने और ऑब्जेक्ट को बदलने की प्रतीक्षा करते हैं तो परमाणुता प्राप्त करने के लिए स्थिति का उपयोग किया जाता है। जब आप किसी शर्त पर प्रतीक्षा करना शुरू करते हैं, तो यह अनलॉक करने के लिए म्यूटेक्स और गारंटी को अनलॉक करता है + प्रतीक्षा करने के लिए कॉल परमाणु है और कोई अन्य थ्रेड उन दो संचालनों के बीच संसाधन को संशोधित नहीं कर सकता है।

सेमफोर, किसी अन्य मामले पर, हालत और म्यूटेक्स का मिश्रण है, और इसका उपयोग उसी उद्देश्य के लिए किया जाता है लेकिन प्रक्रियाओं में पहुंच को सिंक्रनाइज़ करने के लिए किया जाता है।

Mutex vs Semaphore देखें।

non-blocking/lock-free synchronization जैसी चीज भी है जो इन दिनों बहुत लोकप्रिय हो रही है। मैं व्यक्तिगत रूप से उच्च आवृत्ति व्यापार अनुप्रयोगों में इसका उपयोग करता हूं जब डेटा की मात्रा अपेक्षाकृत बहुत बड़ी होती है और कम विलंबता बहुत मायने रखती है।

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

मुझे यकीन नहीं है कि इसे बेहतर तरीके से कैसे वर्णन किया जाए क्योंकि मैं इसके बारे में एक पुस्तक लिखना समाप्त कर दूंगा। इसलिए मैं आपको कुछ ऐसी पुस्तकें ढूंढने की सलाह दूंगा जो बुनियादी अवधारणाओं को समझने के लिए पहले ही लिखी गई हैं। एक बार जब आप मूल बातें जानते हैं, तो आप POSIX threads, Boost Interprocess या Thread, ACE या non-blocking algorithms जैसे एपीआई/लाइब्रेरी/फ्रेमवर्क जैसे आप चाहते हैं प्राप्त करने के लिए उपयोग कर सकते हैं।

शुभकामनाएं!

+0

तो, जिज्ञासा से बाहर, "इंटरप्रोसेस सेमफोर" नाम से पता चलता है कि यह धागे की बजाय प्रक्रियाओं के बीच साझा किया जाना है। क्या इसका मतलब यह है कि सैद्धांतिक रूप से एक इंट्रोप्रोसेस सेमफोर का उपयोग करने के लिए अतिरिक्त ओवरहेड खर्च होता है? मुझे यकीन नहीं है कि सवाल पर मेरी टिप्पणी में उल्लिखित खिलौना आवेदन जैसे अनुप्रयोगों के लिए थ्रेड स्थितियों का आसानी से उपयोग कैसे करें। – jonderry

+0

@jonderry: ठीक है, मैंने सोचा कि मैं एक साधारण उत्तर से दूर हो सकता हूं, लेकिन तुमने मुझे मिल गया। मैंने एक टिप्पणी में जवाब देना शुरू कर दिया है लेकिन यह बहुत सारे लिंक के साथ बहुत बड़ा था इसलिए मैंने अपना जवाब संपादित करना समाप्त कर दिया। कृपया अद्यतन संस्करण देखें। धन्यवाद। –

+0

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

21

बूस्ट का उपयोग करके यह एक बहुत ही सरल सेमफोर को लागू करने का एक तरीका है। थ्रेड। यह एक इंटर-थ्रेड सेमफोर है, एक इंटरप्रोसेस नहीं। कोई वारंटी लागू नहीं है, आदि - मैंने कोड भी संकलित नहीं किया है। यह दिखाता है कि म्यूटेक्स और हालत चर कैसे बातचीत करते हैं, और बूस्ट के एक उचित हाल के संस्करण को मानते हैं।

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

यह सब वास्तव में Vlad Lazarenko के उत्तर के पूरक के रूप में है - सिद्धांत और सिद्धांतों को समझना कम से कम "काम" कोड के रूप में बहु-थ्रेड प्रोग्रामिंग में महत्वपूर्ण है।

#include <boost/thread/condition_variable.hpp> 
#include <boost/thread/mutex.hpp>  
#include <boost/thread/lock_types.hpp> 


class semaphore 
{ 
    //The current semaphore count. 
    unsigned int count_; 

    //mutex_ protects count_. 
    //Any code that reads or writes the count_ data must hold a lock on 
    //the mutex. 
    boost::mutex mutex_; 

    //Code that increments count_ must notify the condition variable. 
    boost::condition_variable condition_; 

public: 
    explicit semaphore(unsigned int initial_count) 
     : count_(initial_count), 
     mutex_(), 
     condition_() 
    { 
    } 

    unsigned int get_count() //for debugging/testing only 
    { 
     //The "lock" object locks the mutex when it's constructed, 
     //and unlocks it when it's destroyed. 
     boost::unique_lock<boost::mutex> lock(mutex_); 
     return count_; 
    } 

    void signal() //called "release" in Java 
    { 
     boost::unique_lock<boost::mutex> lock(mutex_); 

     ++count_; 

     //Wake up any waiting threads. 
     //Always do this, even if count_ wasn't 0 on entry. 
     //Otherwise, we might not wake up enough waiting threads if we 
     //get a number of signal() calls in a row. 
     condition_.notify_one(); 
    } 

    void wait() //called "acquire" in Java 
    { 
     boost::unique_lock<boost::mutex> lock(mutex_); 
     while (count_ == 0) 
     { 
      condition_.wait(lock); 
     } 
     --count_; 
    } 

}; 
+0

एक आकर्षण की तरह काम करता है। बहुत बुरा यह अब बूस्ट का हिस्सा नहीं है। कोड के लिए – Thomas

+0

+ 1। गिनती में ग्यूटक्स के लिए कोई बात है? वैसे भी प्राप्त होने पर गिनती "पुरानी" होगी, है ना? – daramarak

+1

सही, वापस लौटने पर गिनती पुरानी होगी। डिबगिंग के अलावा अन्य कारणों के लिए एक सेमफोर की गिनती प्राप्त करना संभवतः आपके प्रोग्राम में एक बग है। –

0

मैं एक सेमाफोर वर्ग को बूस्ट के साथ संगत TimedLockable अवधारणा बना, तो यह boost::unique_lock<semaphore> तरह ताले के साथ प्रयोग किया जा सकता है।यह एक की शास्त्रीय परिभाषा में एक सेमफोर नहीं है, लेकिन इसका उपयोग एक के रूप में किया जा सकता है। फिर भी, उम्मीद है कि यह किसी के लिए उपयोगी हो सकता है।

किसी भी तरह से इसका परीक्षण किया गया, लेकिन बहुत संभावना है कि मैंने कुछ गलत किया। अगर कोई इसे शुद्धता साबित कर सकता है तो अच्छा होगा।

class semaphore 
{ 
private: 
    semaphore(const semaphore & other); 
    semaphore & operator = (const semaphore & other); 

    boost::mutex _mutex; 
    boost::condition_variable _condVar; 
    size_t _count; 

    class wait_predicate 
    { 
    private: 
     const size_t & _countRef; 
    public: 
     wait_predicate(const size_t & countRef) : _countRef(countRef) {} 
     bool operator()() { return _countRef > 0; } 
    }; 

    // must be used inside a locked scope! 
    inline wait_predicate getWaitPredicate() const 
    { 
     return wait_predicate(_count); 
    } 

public: 
    semaphore(size_t size): _count(size) 
    {} 

    void lock() 
    { 
     boost::unique_lock<boost::mutex> local_lock(_mutex); 
     _condVar.wait(local_lock, getWaitPredicate()); 
     _count--; 
    } 

    void unlock() 
    { 
     boost::unique_lock<boost::mutex> local_lock(_mutex); 
     _count++; 
     _condVar.notify_one(); 
    } 

    bool try_lock() 
    { 
     boost::unique_lock<boost::mutex> local_lock(_mutex); 
     if (0 == _count) 
     return false; 

     _count--; 
     return true; 
    } 

    template <typename Duration> 
    bool try_lock_for(const Duration & duration) 
    { 
     boost::unique_lock<boost::mutex> local_lock(_mutex); 
     if (!_condVar.wait_for(local_lock, duration, getWaitPredicate())) 
     return false; 

     _count--; 
     return true; 
    } 

    template <class TimePoint> 
    bool try_lock_until(const TimePoint & timePoint) 
    { 
     boost::unique_lock<boost::mutex> local_lock(_mutex); 
     if (!_condVar.wait_until(local_lock, timePoint, getWaitPredicate())) 
     return false; 

     _count--; 
     return true; 
    } 

    template <class WaitCriteria> 
    bool timed_lock(const WaitCriteria & criteria) 
    { 
     boost::unique_lock<boost::mutex> local_lock(_mutex); 
     if (!_condVar.timed_wait(local_lock, criteria, getWaitPredicate())) 
     return false; 

     _count--; 
     return true; 
    } 
}; 
संबंधित मुद्दे

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