2015-05-23 56 views
3

我有一個關於線程安全性和互斥鎖的問題。我有可能無法在同一時間執行,因爲這可能會導致問題的兩個功能:C++:爲其他函數鎖定互斥鎖,但本身可以並行執行的函數

std::mutex mutex; 

void A() { 
    std::lock_guard<std::mutex> lock(mutex); 
    //do something (should't be done while function B is executing) 
} 

T B() { 
    std::lock_guard<std::mutex> lock(mutex); 
    //do something (should't be done while function A is executing) 
    return something; 
} 

現在的問題是,該函數A和B不應該在同一時間執行。這就是我使用互斥鎖的原因。但是,如果函數B是從多個線程同時調用的,那就很好了。但是,這也被互斥鎖阻止了(我不希望這樣)。現在有沒有辦法確保A和B不能同時執行,而仍然讓函數B並行執行多次?

+0

也許使用某種信號量來跟蹤每個函數的當前調用者的數量? –

回答

3

如果C++ 14是一個選項,你可以使用一個共享的互斥體(有時稱爲「讀寫器」的互斥體)。基本上,內部功能A()你會獲得一個獨特的(獨家,「作家」)鎖,而在功能B()內,你將獲得一個共享(非獨佔,「讀者」)鎖。

只要共享鎖存在,互斥鎖就不能被其他線程獲取(但可以非唯一地獲取);只要存在排他鎖,互斥鎖就無法被任何其他線程獲取。

的結果是,你可以有多個線程同時執行的功能B(),而功能A()執行防止兩者A()B()被其他線程的併發執行:

#include <shared_mutex> 

std::shared_timed_mutex mutex; 

void A() { 
    std::unique_lock<std::shared_timed_mutex> lock(mutex); 
    //do something (should't be done while function B is executing) 
} 

T B() { 
    std::shared_lock<std::shared_timed_mutex> lock(mutex); 
    //do something (should't be done while function A is executing) 
    return something; 
} 

注意,一些同步開銷會即使在併發執行B()時也總是存在,並且這是否會最終提供比使用普通互斥鎖更好的性能,這高度依賴於這些函數內外發生的事情 - 總是在提交更復雜的解決方案之前進行測量。

Boost.Thread還提供了shared_mutex的實現。

+0

謝謝。不幸的是我的編譯器還不支持C++ 14。 – user1488118

+0

@ user1488118:正如我在答案中所述,「Boost.Thread還提供了'shared_mutex'的實現。」在上面的代碼片段(哦,以及'boost :: shared_mutex'包含的'std :: shared_timed_mutex')中,無處不在用'boost ::'替換'std ::'就足夠了。 –

0

這很可能是完全錯誤的,但因爲你沒有C++ 14,你可以圍繞std::mutex創建一個鎖定計數包裝和使用:

// Lock-counting class 
class SharedLock 
{ 
public: 
    SharedLock(std::mutex& m) : count(0), shared(m) {} 

    friend class Lock; 

    // RAII lock 
    class Lock 
    { 
    public: 
     Lock(SharedLock& l) : lock(l) { lock.lock(); } 
     ~Lock()      { lock.unlock(); } 
    private: 
     SharedLock& lock; 
    }; 

private: 

    void lock() 
    { 
     std::lock_guard<std::mutex> guard(internal); 
     if (count == 0) 
     { 
     shared.lock(); 
     } 
     ++count; 
    } 


    void unlock() 
    { 
     std::lock_guard<std::mutex> guard(internal); 
     --count; 
     if (count == 0) 
     { 
     shared.unlock(); 
     } 
    } 

    int count; 
    std::mutex& shared; 
    std::mutex internal; 
}; 

std::mutex shared_mutex; 

void A() 
{ 
    std::lock_guard<std::mutex> lock(shared_mutex); 
    // ... 
} 


void B() 
{ 
    static SharedLock shared_lock(shared_mutex); 
    SharedLock::Lock mylock(shared_lock); 
    // ... 
} 

...除非你想潛水當然,進入Boost。