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

无主互斥锁
EN

Stack Overflow用户
提问于 2020-01-08 02:02:03
回答 2查看 2.5K关注 0票数 4

我创建了下面的类,它提供了一个acquire_lock()release_lock()函数

代码语言:javascript
复制
class LockableObject {

public:

    void acquire_lock() {
        std::unique_lock<std::mutex> local_lock(m_mutex);
        m_lock = std::move(local_lock);
    }

    void release_lock() {
        m_lock.unlock();
    }

private:

    std::mutex m_mutex;

    std::unique_lock<std::mutex> m_lock;
};

该类提供了一个acquire_lockrelease_lock函数。在执行任何操作之前,我有多个线程访问同一个对象并调用acquire_lock,然后按照下面的步骤调用release_lock

代码语言:javascript
复制
void ThreadFunc(int ID, LockableObject* lckbleObj)
{
    for (int i = 0; i < 1000; i++)
    {
        lckbleObj->acquire_lock();
        std::cout << "Thread with ID = " << ID << "doing work" << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        lckbleObj->release_lock();
    }
}



void main()
{
    const int numThreads = 10;
    std::thread workerThreads[numThreads];
    LockableObject *testObject = new LockableObject();

    for (int i = 0; i < numThreads; i++)
    {
        workerThreads[i] = std::thread(ThreadFunc, i, testObject);
    }

    for (int i = 0; i < numThreads; i++)
    {
        workerThreads[i].join();
    }
}

acquire_lock函数中,我首先尝试通过在构造函数中传递底层互斥锁(m_mutex),将其传递给本地堆栈std::unique_lock对象。我假设一旦std::unique_lock的构造函数返回,它就锁定了互斥锁,然后我将堆栈上的unique_lock移动到成员变量m_lock

这个程序在一些基本的方面是有缺陷的,在调用release_lock时会导致"unlock of unowned mutex",我似乎缺少一些关于std::unique_lock的基本内容,并且正在寻找一个人来纠正我的理解。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-01-08 02:30:41

请参阅我关于构造函数中缺少std::defer_lock的评论。但是,您的代码中也有一个竞赛条件。

acquire_lock函数在m_lock互斥体的保护下修改m_mutex。因此,为了确保线程安全,除了保存m_lock之外,任何其他线程都不能修改m_mutex

但是release_lock函数在释放互斥体时会修改m_lock。因此,在m_lock上没有适当的同步。

这是有点微妙的理解。这是问题代码:

代码语言:javascript
复制
    m_lock.unlock();

请注意,当输入此函数时,m_mutex被锁定,但在其执行期间,它将修改m_lock并以不确定的顺序释放m_mutex。但m_mutex保护m_lock。所以这是比赛条件,是不允许的。

它可以固定如下:

代码语言:javascript
复制
void release_lock() {
    std::unique_lock<std::mutex> local_lock = std::move(m_lock);
    local_lock.unlock();
}

现在,这第一行代码修改了m_lock,但运行时完全使用了m_mutex held。这就避免了比赛的条件。

如果需要,可以删除unlocklocal_lock的析构函数将完成这一任务。

顺便提一下,我建议修改API。而不是提供锁定和解锁调用,而是创建一个拥有该对象的锁的对象。如果您愿意,甚至可以使用std::unique_lock<LockableObject>。为什么要创建一个比标准提供的API更糟糕的新API呢?

票数 6
EN

Stack Overflow用户

发布于 2020-01-08 02:36:11

成员函数acquire_lock可以更改如下所示,以解决此问题:

代码语言:javascript
复制
void acquire_lock() {
    m_lock = std::unique_lock<std::mutex>(m_mutex);
}

将调用移动-分配函数 of unique_lock来管理m_lock中的互斥对象m_mutex

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

https://stackoverflow.com/questions/59638470

复制
相关文章

相似问题

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