簡體   English   中英

交換互斥鎖

[英]Swapping mutex locks

我在正確地“交換”鎖時遇到了麻煩。 考慮這種情況:

bool HidDevice::wait(const std::function<bool(const Info&)>& predicate)
{
    /* A method scoped lock. */
    std::unique_lock waitLock(this->waitMutex, std::defer_lock);

    /* A scoped, general access, lock. */
    {
        std::lock_guard lock(this->mutex);

        bool exitEarly = false;

        /* do some checks... */

        if (exitEarly)
            return false;

        /* Only one thread at a time can execute this method, however
        other threads can execute other methods or abort this one. Thus,
        general access mutex "this->mutex" should be unlocked (to allow threads
        to call other methods) while at the same time, "this->waitMutex" should
        be locked to prevent multiple executions of code below. */

        waitLock.lock(); // How do I release "this->mutex" here?
    }

    /* do some stuff... */

    /* The main problem is with this event based OS function. It can 
    only be called once with the data I provide, therefore I need to 
    have a 2 locks - one blocks multiple method calls (the usual stuff) 
    and "waitLock" makes sure that only one instance of "osBlockingFunction" 
    is ruinning at the time. Since this is a thread blocking function,
    "this->mutex" must be unlocked at this point. */

    bool result = osBlockingFunction(...);

    /* In methods, such as "close", "this->waitMutex" and others are then used 
    to make sure that thread blocking methods have returned and I can safely
    modify related data. */

    /* do some more stuff... */

    return result;
}

我如何解決這個“交換”問題而又不使代碼過於復雜? 我可以先鎖定this->mutex然后再鎖定另一個,但是我擔心在那一納秒內會發生競爭。

編輯:

想象一下,有3個線程正在調用wait方法。 第一個將鎖定this->mutex ,然后鎖定this->mutex this->waitMutex ,然后將其解鎖this->mutex 第二個將鎖定this->mutex並且必須等待this->waitMutex可用。 它不會解鎖this->mutex 第三個將卡在鎖定this->mutex

我想讓最后2個線程等待this->waitMutex可用。

編輯2:

擴展了osBlockingFunction示例。

聞起來好像與HidDevice::wait上的std::condition_variable cv的設計/實現應該有點不同,並且只有一個互斥體。 當您編寫“其他線程可以執行其他方法或中止該方法”時,將調用cv.notify_one來“中止”該等待。 cv.wait {自動輸入等待並解鎖互斥鎖},而在cv.notify {自動cv.notify等待並鎖定互斥鎖}。 像那HidDevice::wait更簡單:

bool HidDevice::wait(const std::function<bool(const Info&)>& predicate)
{
    std::unique_lock<std::mutex> lock(this->m_Mutex); // Only one mutex.

    m_bEarlyExit = false;

    this->cv.wait(lock,  spurious wake-up check);

    if (m_bEarlyExit) // A bool data-member for abort. 
        return;

    /* do some stuff... */
}
  • 我的假設是(根據函數的名稱)在/* do some checks... */線程等待直到某些邏輯變為真。

“中止”等待,將由另一個線程調用其他HidDevice函數的責任:

void HidDevice::do_some_checks() /* do some checks... */
{
    if ( some checks )
    {
        if ( other checks )
            m_bEarlyExit = true;

        this->cv.notify_one();
    }
}

類似的東西。

我建議創建一個小的“解鎖”工具。 這是具有反向語義的互斥包裝。 lock它會unlocks ,反之亦然:

template <class Lock>
class unlocker
{
    Lock& locked_;

public:
    unlocker(Lock& lk) : locked_{lk} {}

    void lock() {locked_.unlock();}
    bool try_lock() {locked_.unlock(); return true;}
    void unlock() {locked_.lock();}
};

現在代替:

waitLock.lock(); // How do I release "this->mutex" here?

您可以說:

unlocker temp{lock};
std::lock(waitLock, temp);

其中lockunique_lock而不是持有mutexlock_guard

這將鎖定waitLock並解鎖mutex ,就像通過一條不間斷的指令一樣。


現在,在對所有這些進行編碼之后,我可以推斷它可以轉換為:

waitLock.lock();
lock.unlock();  // lock must be a unique_lock to do this

第一版本的可讀性或高或低是一個問題。 第一個版本更容易推論(一旦知道std::lock作用)。 但是第二個更簡單。 但是第二點,讀者必須更仔細地考慮正確性。


更新

只需閱讀問題中的編輯內容即可。 此解決方案不能解決編輯中的問題:第二個線程將阻止第三個(及后續線程)在需要mutex但不需要waitMutex任何代碼中取得進展,直到第一個線程釋放waitMutex

因此,從這個意義上講,我的回答在技術上是正確的,但不滿足所需的性能特征。 我將其留作參考。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM