2012-10-02 7 views
8

मैं एक दो धागे, जिनमें एक तंग पाश में काम करता है, और अन्य जो कभी कभी पहले के साथ एक समन्वयन करने की जरूरत है:pthreads: धागा भुखमरी की वजह से जल्दी फिर से ताला लगा

// thread 1 
while(1) 
{ 
    lock(work); 
    // perform work 
    unlock(work); 
} 

// thread 2 
while(1) 
{ 
    // unrelated work that takes a while 
    lock(work); 
    // synchronizing step 
    unlock(work); 
} 

मेरे इरादे क्या यह थ्रेड 2 लॉक ले कर प्रभावी ढंग से थ्रेड 1 रोक सकता है और आवश्यक सिंक्रनाइज़ेशन कर सकता है। थ्रेड 1 अनलॉक करके, रोकें, और थ्रेड 2 लॉक पर इंतजार नहीं कर रहा है, फिर से लॉक और काम पर लौट सकता है।

समस्या मैं सामना करना पड़ा है कि mutexes निष्पक्ष नहीं हैं, इसलिए जल्दी से 1 थ्रेड फिर से ताले म्युटेक्स और धागा 2. मैं pthread_yield का उपयोग करने का प्रयास किया starves, और अब तक यह ठीक से चलाने के लिए लगता है, लेकिन मैं नहीं कर रहा हूँ है सुनिश्चित करें कि यह सभी प्रणालियों/कोरों की संख्या के लिए काम करेगा। क्या गारंटी देने का कोई तरीका है कि थ्रेड 1 हमेशा बहु-कोर सिस्टम पर थ्रेड 2 तक पहुंच जाएगा?

इस सिंक्रनाइज़ेशन प्रक्रिया को संभालने का सबसे प्रभावी तरीका क्या है?

+0

क्या आप अपने प्रश्न में वर्णन किया है, निष्पक्षता से कोई संबंध नहीं है। – Michael

+0

यह प्रश्न [* मेला महत्वपूर्ण अनुभाग (लिनक्स) *] (http://stackoverflow.com/q/6449732/134633) के समान है। – caf

उत्तर

3

आप pthreads mutexes के शीर्ष पर एक फीफो "टिकट लॉक", इन पंक्तियों के साथ निर्माण कर सकते हैं:

#include <pthread.h> 

typedef struct ticket_lock { 
    pthread_cond_t cond; 
    pthread_mutex_t mutex; 
    unsigned long queue_head, queue_tail; 
} ticket_lock_t; 

#define TICKET_LOCK_INITIALIZER { PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER } 

void ticket_lock(ticket_lock_t *ticket) 
{ 
    unsigned long queue_me; 

    pthread_mutex_lock(&ticket->mutex); 
    queue_me = ticket->queue_tail++; 
    while (queue_me != ticket->queue_head) 
    { 
     pthread_cond_wait(&ticket->cond, &ticket->mutex); 
    } 
    pthread_mutex_unlock(&ticket->mutex); 
} 

void ticket_unlock(ticket_lock_t *ticket) 
{ 
    pthread_mutex_lock(&ticket->mutex); 
    ticket->queue_head++; 
    pthread_cond_broadcast(&ticket->cond); 
    pthread_mutex_unlock(&ticket->mutex); 
} 

योजना के इस प्रकार के तहत कोई भी निम्न स्तर pthreads म्युटेक्स जबकि एक धागा भीतर है आयोजित किया जाता है टिकटॉक ने महत्वपूर्ण खंड को संरक्षित किया, जिससे अन्य धागे कतार में शामिल हो गए।

5

अपने मामले में condition variable का उपयोग करना बेहतर है ताकि दूसरे थ्रेड को सूचित किया जा सके जब इसे जागने और सभी आवश्यक संचालन करने की आवश्यकता हो।

+1

कृपया इस तरह की समस्याओं के संभावित समाधान के रूप में सेमफोरों का भी उल्लेख करें, उन्हें अक्सर अनदेखा किया जाता है! –

+0

इस समस्या के लिए सेफफोर्स का उपयोग कैसे किया जा सकता है इसके बारे में कोई उदाहरण या स्निपेट? – Atanu

+0

[मेरा यह जवाब] (http://stackoverflow.com/a/6453925/134633) उपयोगी हो सकता है, जहां मैं दिखाता हूं कि पहले-इन-फर्स्ट-आउट टिकट लॉक को लागू करने के लिए pthreads condition चर का उपयोग कैसे करें। – caf

2

pthread अपने एपीआई में थ्रेड प्राथमिकता की धारणा प्रदान करता है। जब दो धागे एक म्यूटेक्स पर प्रतिस्पर्धा कर रहे हैं, शेड्यूलिंग नीति यह निर्धारित करती है कि कौन सा इसे प्राप्त करेगा। फ़ंक्शन pthread_attr_setschedpolicy आपको इसे सेट करने देता है, और pthread_attr_getschedpolicy जानकारी पुनर्प्राप्त करने की अनुमति देता है।

अब बुरी खबर:

  • जब केवल दो धागे को लॉक कर/एक म्युटेक्स को अनलॉक करने, मैं, प्रतियोगिता के किसी भी प्रकार नहीं देख सकते हैं पहले जो परमाणु अनुदेश चलाता है यह लेता है, तो दूसरा रोकता है। मुझे यकीन नहीं है कि यह विशेषता यहां लागू होती है या नहीं।
  • समारोह विभिन्न मापदंडों (SCHED_FIFO, SCHED_RR, SCHED_OTHER और SCHED_SPORADIC), लेकिन in this question ले जा सकते हैं, यह जवाब दिया गया है कि केवल SCHED_OTHER लिनक्स पर समर्थित किया गया)

तो मैं इसे एक शॉट देना होगा अगर मैं थे आप, लेकिन बहुत ज्यादा उम्मीद नहीं है। pthread_yield मेरे लिए अधिक आशाजनक प्रतीत होता है। अधिक जानकारी here उपलब्ध है।

0

ऊपर टिकट लॉक सबसे अच्छा दिखता है। हालांकि, अपने pthread_yield कार्यों को बीमा करने के लिए, आप एक बूल प्रतीक्षा कर सकते हैं, जो सेट 2 द्वारा सेट और रीसेट किया गया है। जब तक बूल प्रतीक्षा सेट हो जाता है तब तक थ्रेड 1 पैदा होता है।

0

यहां एक आसान समाधान है जो आपके मामले (दो धागे) के लिए काम करेगा। यदि आप std::mutex का उपयोग कर रहे हैं तो यह कक्षा एक ड्रॉप-इन प्रतिस्थापन है। अपने म्यूटेक्स को इस प्रकार में बदलें और आपको गारंटी है कि यदि एक थ्रेड लॉक रखता है और दूसरा उस पर इंतजार कर रहा है, तो पहला थ्रेड अनलॉक हो जाने पर, दूसरा धागा लॉक को पहले लॉक से पहले लॉक कर लेगा।

यदि दो से अधिक थ्रेड एक साथ mutex का उपयोग करने के लिए होता है तो यह अभी भी कार्य करेगा लेकिन निष्पक्षता पर कोई गारंटी नहीं है।

यदि आप सादे pthread_mutex_t का उपयोग कर रहे हैं तो आप इस उदाहरण के अनुसार आसानी से अपना लॉकिंग कोड बदल सकते हैं (अनलॉक अपरिवर्तित बनी हुई है)। आप थ्रेड 2 उच्च प्राथमिकता के साथ रहना चाहते हैं, तो 1, तरीकों में से एक थ्रेड, इसे प्राप्त करने के हालत वेरिएबल का उपयोग कर

#include <mutex> 

// Behaves the same as std::mutex but guarantees fairness as long as 
// up to two threads are using (holding/waiting on) it. 
// When one thread unlocks the mutex while another is waiting on it, 
// the other is guaranteed to run before the first thread can lock it again. 

class FairDualMutex : public std::mutex { 
public: 
    void lock() { 
     _fairness_mutex.lock(); 
     std::mutex::lock(); 
     _fairness_mutex.unlock(); 
    } 
private: 
    std::mutex _fairness_mutex; 
};