lock_guard是否保护返回值
Does a lock_guard protect the return value?
我有一个关于lock_guard
s和返回值的问题。我想用一些代码来说明我的问题:
class Semaphore
{
public:
Semaphore() = delete;
Semaphore(int n);
/**
* Increases semaphore by one.
*/
void up()
{
std::lock_guard<std::mutex> lg(m_);
++n_;
}
/**
* Decreases semaphore by one.
*/
void down()
{
std::lock_guard<std::mutex> lg(m_);
--n_;
}
/**
* Returns the underlying value of the semaphore.
*/
int get1() const
{
std::lock_guard<std::mutex> lg(m_);
int tmp = n_;
return tmp;
}
/**
* Returns the underlying value of the semaphore.
*/
int get2() const
{
std::lock_guard<std::mutex> lg(m_);
return n_;
}
private:
mutable std::mutex m_;
int n_;
};
上面的类是Semaphore
的一个简单实现。哪种get方法是线程安全的?get2
足够好吗?还是我必须使用get1
?我必须将内部值n_
复制到一个临时变量吗?或者我可以立即返回它吗?
这篇文章可以归结为一个问题:lock_guard是否保护我的退货价值
get2()
足以保护返回值。
n_
是按值返回的,因此会生成一个变量副本,以便将其与return n_
语句一起返回给调用者。您的lock_guard
将确保n_
不会被更改,直到该副本返回给调用者,然后它被销毁,从而释放锁。
退回副本是正确的,但不会给您带来任何额外的好处。此外,在任何情况下,您都需要维护锁,直到副本也返回为止。因此,使用get1
,除非编译器对其进行优化,否则您将为额外的副本分配付费,而不会获得太多收益。
两个版本是相等的。在销毁std::lock_guard
之前创建返回值。
您可以使用下一个代码片段对此进行测试
#include <iostream>
#include <memory>
#include <mutex>
template <typename T>
struct GuardWrapper : std::lock_guard<T> {
GuardWrapper(T &e) : std::lock_guard<T>(e) { std::cout << "Creating guard" << std::endl; }
~GuardWrapper() { std::cout << "Deleting guard" << std::endl; }
};
struct A {
A() { std::cout << "Creating A" << std::endl; }
A(const A& other) {
*this = other;
std::cout << "Copying A" << std::endl;
}
~A() { std::cout << "Deleting A" << std:: endl; }
};
struct B {
A test() {
GuardWrapper<std::mutex> guard(m_);
return a_;
}
A test_with_tmp() {
GuardWrapper<std::mutex> guard(m_);
A tmp = a_;
return tmp;
}
private:
std::mutex m_;
A a_;
};
int main () {
std::cout << "init" << std::endl;
B b;
std::cout << "try without temp" << std::endl;
A a0 = b.test();
std::cout << "try with temp" << std::endl;
A a1 = b.test_with_tmp();
std::cout << "cleanup" << std::endl;
}
输出为
init
Creating A
try without temp
Creating guard
Copying A
Deleting guard
try with temp
Creating guard
Copying A
Deleting guard
cleanup
Deleting A
Deleting A
Deleting A
相关文章:
- 从python中调用C++函数并获取返回值
- 为什么模板类中的对象不能返回值
- 返回值优化:显式移动还是隐式
- lock_guard是否保护返回值
- 调用CreateProcess()并获取字符串的返回值
- 如何使 windows 命令提示符在C++可执行文件上显示返回值?
- 编译器警告:执行到达值返回函数的末尾而不返回值
- 查找 GCD:并非所有控制路径都返回值
- 在 Arduino 上使用 sscanf 会导致与 const char * 不匹配,并且返回值始终相同,尽管输入值不同
- 将返回值存储在函数指针数组的指针中是如何工作的?
- 如何从 std::thread 返回值
- 将返回值从 exe 传递到 bat,并将其传递给 C# 中的进程
- 方法错误"not all control paths return a value"和方法不返回值
- 如何读取 C++ SAFEARRAY**,该 SAFEARRAY** 是 COM 互操作的结果,其中 C# 返回值为
- 对fread的返回值感到困惑
- 程序不向函数返回值
- 如何在另一个函数中使用返回值作为参数?
- 如何使用 uint64_t 键类型从 std::map<int, std::string> 返回值?
- 使用 std::p air 进行返回值优化
- 基于范围的锁保护和返回值的计时