2012-10-02 63 views
8

我有兩個線程,其中一個在緊密循環工作,以及偶爾需要執行與第一同步其他:並行線程:造成線程飢餓快速的重新鎖定

// 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沒有等待鎖定,則重新鎖定並返回工作。

我遇到的問題是互斥體不公平,所以線程1很快重新鎖定了互斥體並且導致線程2不能正常運行。我試圖使用pthread_yield,並且目前爲止它似乎運行正常,但我不是確保它適用於所有系統/內核數量。有沒有辦法保證即使在多核系統上,線程1也會始終屈服於線程2?

處理此同步過程的最有效方法是什麼?

+0

你在你的問題已經描述了沒有關係公平,如果你想線程2是具有較高優先級線程,然後1,一個的方式來實現這一目標,通過使用條件變量。 – Michael

+0

這個問題與[* Fair fair section(Linux)*](http://stackoverflow.com/q/6449732/134633)非常相似。 – caf

回答

3

你可以建立一個FIFO「票鎖定」在並行線程互斥體的頂部,沿着這些路線:

#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); 
} 

在這種方案中,沒有低級並行線程互斥舉行,而一個線程中ticketlock保護關鍵部分,允許其他線程加入隊列。

5

在你的情況下,最好使用condition variable通知第二個線程,當它需要喚醒並執行所有必需的操作時。

+1

也請提到信號量作爲解決這些問題的潛在解決方案,它們經常被忽視! –

+0

有關信號量如何用於解決此問題的任何示例或代碼片段? – Atanu

+0

[這是我的回答](http://stackoverflow.com/a/6453925/134633)可能很有用,我將展示如何使用pthreads條件變量實現先進先出門票鎖定。 – caf

2

pthread在其API中提供了線程優先級的概念。當兩個線程在互斥體上競爭時,調度策略決定哪個線程獲得它。功能pthread_attr_setschedpolicy可讓您設置,pthread_attr_getschedpolicy允許檢索信息。

現在的壞消息:

  • 當只有兩個線程鎖定/解鎖互斥,我看不到任何形式的競爭,誰運行的原子指令需要它,其他區塊的第一。我不確定這個屬性是否適用於此。
  • 功能可以採取不同的參數(SCHED_FIFOSCHED_RRSCHED_OTHERSCHED_SPORADIC),但in this question,它已經回答了,只有SCHED_OTHER在Linux平臺支持)

所以我給它一個鏡頭,如果我是你,但不要指望太多。 pthread_yield對我來說似乎更有希望。更多信息here

0

上面的票務鎖看起來像最好的。但是,爲了確保您的pthread_yield能夠正常工作,您可以等待一個bool,它由thread2進行設置和重置。只要布爾等待被設置,thread1就會產生。

0

下面是一個簡單的解決方案,將爲您的情況(兩個線程)工作。如果你使用的是std::mutex,那麼這個類是一個直接替換。將你的互斥鎖改爲這種類型,並保證如果一個線程持有鎖而另一個線程等待它,一旦第一個線程解鎖,第二個線程將在第一個線程再次鎖定之前獲取該鎖。

如果有兩個以上的線程同時使用互斥鎖,它仍然可以正常工作,但不能保證公平性。

如果您使用普通pthread_mutex_t,則可以根據此示例輕鬆更改鎖定代碼(解鎖保持不變)。

#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; 
};