解锁无主互斥锁

aru*_*sun 4 c++

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

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;
};
Run Code Online (Sandbox Code Playgroud)

这个类提供了一个acquire_lockrelease_lock函数。我有多个线程访问同一个对象并acquire_lock在执行任何操作之前调用 ,然后调用release_lock一次,如下所示。

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

该程序在某些基本方面存在缺陷,在调用期间release_lock将导致"unlock of unowned mutex",我似乎缺少一些基本的东西std::unique_lock,正在寻找人来纠正我的理解。

Dav*_*rtz 6

请参阅我std::defer_lock对构造函数中缺少的评论。但是您的代码中也存在竞争条件。

acquire_lock函数修改互斥锁的m_lock保护不足m_mutex。因此,为了确保线程安全,m_lock除了持有 之外,其他线程都不能修改m_mutex

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

这有点难以理解。这是问题代码:

    m_lock.unlock();
Run Code Online (Sandbox Code Playgroud)

请注意,当此函数被输入时,m_mutex被锁定,但在其执行期间,它以没有特定保证的顺序修改m_lock和释放m_mutex。而是m_mutex保护m_lock。所以这是一种竞争条件,是不允许的。

它可以固定如下:

void release_lock() {
    std::unique_lock<std::mutex> local_lock = std::move(m_lock);
    local_lock.unlock();
}
Run Code Online (Sandbox Code Playgroud)

现在,这第一行代码修改m_lock但完全m_mutex保持运行。这避免了竞争条件。

unlock如果需要,可以将其移除。的析构函数local_lock会这样做。

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