我创建了下面的类,它提供了一个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;
};该类提供了一个acquire_lock和release_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();
}
}在acquire_lock函数中,我首先尝试通过在构造函数中传递底层互斥锁(m_mutex),将其传递给本地堆栈std::unique_lock对象。我假设一旦std::unique_lock的构造函数返回,它就锁定了互斥锁,然后我将堆栈上的unique_lock移动到成员变量m_lock。
这个程序在一些基本的方面是有缺陷的,在调用release_lock时会导致"unlock of unowned mutex",我似乎缺少一些关于std::unique_lock的基本内容,并且正在寻找一个人来纠正我的理解。
发布于 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上没有适当的同步。
这是有点微妙的理解。这是问题代码:
m_lock.unlock();请注意,当输入此函数时,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();
}现在,这第一行代码修改了m_lock,但运行时完全使用了m_mutex held。这就避免了比赛的条件。
如果需要,可以删除unlock。local_lock的析构函数将完成这一任务。
顺便提一下,我建议修改API。而不是提供锁定和解锁调用,而是创建一个拥有该对象的锁的对象。如果您愿意,甚至可以使用std::unique_lock<LockableObject>。为什么要创建一个比标准提供的API更糟糕的新API呢?
发布于 2020-01-08 02:36:11
成员函数acquire_lock可以更改如下所示,以解决此问题:
void acquire_lock() {
m_lock = std::unique_lock<std::mutex>(m_mutex);
}将调用移动-分配函数 of unique_lock来管理m_lock中的互斥对象m_mutex。
https://stackoverflow.com/questions/59638470
复制相似问题