我想要返回std::vector
。可以从其他线程(读取和写入)访问此std::vector
。如何在函数完成返回后解锁我的std::mutex
?
例如:
// Value.cpp
std::vector<int> GetValue()
{
std::lock_guard<std::mutex> lock(mutex);
// Do super smart stuff here
// ...
return m_value;
}
// MyThread.cpp
auto vec = myVec.GetValue();
现在如果“在这里做超级聪明的东西”是空的,那该怎么办呢?
// Value.cpp
std::vector<int> GetValue()
{
std::lock_guard<std::mutex> lock(mutex);
return m_value;
}
// MyThread.cpp
auto vec = myVec.GetValue();
那么锁仍然是强制性的吗?为什么?
答案 0 :(得分:16)
使用std::lock_guard
来处理通过RAII锁定和解锁mutex
,这就是它的用途。
int foo()
{
std::lock_guard<std::mutex> lg(some_mutex); // This now locked your mutex
for (auto& element : some_vector)
{
// do vector stuff
}
return 5;
} // lg falls out of scope, some_mutex gets unlocked
在foo
返回后,lg
将超出范围,而unlock
some_mutex
则会超出范围。
答案 1 :(得分:9)
这是印刷语句可以真正帮助的那种问题。例如:
#include <mutex>
#include <iostream>
std::mutex mut;
template <class Mutex>
class Lock
{
Mutex& mut_;
public:
~Lock()
{
std::cout << "unlock\n";
mut_.unlock();
}
Lock(const Lock&) = delete;
Lock& operator=(const Lock&) = delete;
Lock(Mutex& mut)
: mut_(mut)
{
mut_.lock();
std::cout << "lock\n";
}
};
struct A
{
~A()
{
std::cout << "~A() : " << this << "\n";
}
A()
{
std::cout << "A() : " << this << "\n";
}
A(const A& a)
{
std::cout << "A(const A&) : " << this << ", " << &a << "\n";
}
A& operator=(const A& a)
{
std::cout << "A& operator=(const A&) : " << this << ", " << &a << "\n";
return *this;
}
};
A a;
A
get()
{
Lock<std::mutex> lk(mut);
return a;
}
int
main()
{
std::cout << "Start\n";
auto vec = get();
std::cout << "End\n";
}
通过制作我自己的std::lock_guard
版本,我可以插入print语句来找出互斥锁被锁定和解锁的时间。
通过伪造std::vector
(上面称为A
),我可以将印刷语句插入到我感兴趣的特殊成员中。对我来说,这个输出:
A() : 0x10fcfb188
Start
lock
A(const A&) : 0x7fff4ff06b28, 0x10fcfb188
unlock
End
~A() : 0x7fff4ff06b28
~A() : 0x10fcfb188
清楚地表明,在复制0x10fcfb188的A
时,互斥锁被锁定。
可以通过以下方式更改测试以进行分配:
int
main()
{
A vec;
std::cout << "Start\n";
vec = get();
std::cout << "End\n";
}
现在输出:
A() : 0x10d8a7190
A() : 0x7fff5235ab28
Start
lock
A(const A&) : 0x7fff5235ab18, 0x10d8a7190
unlock
A& operator=(const A&) : 0x7fff5235ab28, 0x7fff5235ab18
~A() : 0x7fff5235ab18
End
~A() : 0x7fff5235ab28
~A() : 0x10d8a7190
首先,看起来分配发生在锁外,因此看起来不安全。但是,经过仔细检查,可以看到0x10d8a7190处的受保护A
被复制到锁内的临时A
。然后解锁互斥锁,并从临时到本地进行分配。没有其他线程可能引用临时。因此,只要没有其他线程引用vec
,这又是安全的。