首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >交换互斥锁

交换互斥锁
EN

Stack Overflow用户
提问于 2018-07-15 21:37:03
回答 2查看 698关注 0票数 2

我很难正确地“换”锁。考虑一下这种情况:

代码语言:javascript
复制
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->waitMutex,然后解锁this->mutex。第二个锁将锁定this->mutex,必须等待this->waitMutex可用。它不会解锁this->mutex。第三个会被锁在this->mutex上。

我想让最后两个线程等待this->waitMutex可用。

编辑2:

osBlockingFunction扩展示例。

EN

回答 2

Stack Overflow用户

发布于 2018-07-15 22:04:04

看起来,std::condition_variable cvHidDevice::wait上的设计/实现应该有点不同,只有一个互斥对象。当您编写“其他线程可以执行其他方法或中止此方法”时,将调用cv.notify_one以“中止”此等待。cv.wait {输入、等待和解锁互斥},在cv.notify {退出等待并以原子方式锁定互斥锁。就像这样,HidDevice::wait更简单:

代码语言:javascript
复制
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函数负责:

代码语言:javascript
复制
void HidDevice::do_some_checks() /* do some checks... */
{
    if ( some checks )
    {
        if ( other checks )
            m_bEarlyExit = true;

        this->cv.notify_one();
    }
}

类似的东西。

票数 3
EN

Stack Overflow用户

发布于 2018-07-15 22:12:20

我建议建立一个小小的“解锁”设施。这是一个具有反向语义的互斥包装器。在lock it unlocks和反之亦然:

代码语言:javascript
复制
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();}
};

现在取代:

代码语言:javascript
复制
waitLock.lock(); // How do I release "this->mutex" here?

相反,你可以说:

代码语言:javascript
复制
unlocker temp{lock};
std::lock(waitLock, temp);

其中lockunique_lock而不是lock_guard holding mutex

这将锁定waitLock和解锁mutex,就像通过一个不间断的指令。

现在,在编写所有这些代码之后,我可以推断它可以转换为:

代码语言:javascript
复制
waitLock.lock();
lock.unlock();  // lock must be a unique_lock to do this

第一个版本的可读性是多的还是少的,这是一个意见问题。第一个版本更容易推理(一旦知道std::lock做了什么)。但第二个更简单。但对于第二个问题,读者必须更仔细地思考其正确性。

更新

只需阅读问题中的编辑。此解决方案没有解决编辑中的问题:第二个线程将阻止第三个线程(以及后面的线程)在任何需要mutex而不是waitMutex的代码中取得进展,直到第一个线程释放waitMutex为止。

因此,在这个意义上,我的答案在技术上是正确的,但不符合预期的性能特征。我会把它放在一边,以供参考。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51352436

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档