接受并 return lambda(锁定包装器)
Accept and return lambda (lock wrapper)
我想接受任何 lambda,以便它可以在 lock_guard
下安全地执行一些操作,然后 return 任何东西,但是如下所示使用会引发错误:
#include <iostream>
#include <functional>
#include <mutex>
#include <memory>
class Test {
public:
template<typename Ret>
Ret DoLocked(std::function<Ret(Test&)> func) {
std::lock_guard<std::mutex> lock(*mtx);
return func(*this);
}
private:
std::unique_ptr<std::mutex> mtx = std::make_unique<std::mutex>();
};
int main() {
Test a;
a.DoLocked([](Test &s) {
std::cout << "in do locked" << std::endl;
});
return 0;
}
[build] /some-path/test.cc:21:6: error: no matching function for call to ‘Test::DoLocked(main()::<lambda(Test&)>)’
[build] 21 | });
[build] | ^
[build] /some-path/test.cc:9:13: note: candidate: ‘template<class Ret> Ret Test::DoLocked(std::function<Ret(Test&)>)’
[build] 9 | Ret DoLocked(std::function<Ret(Test&)> func) {
[build] | ^~~~~~~~
[build] /some-path/test.cc:9:13: note: template argument deduction/substitution failed:
[build] /some-path/test.cc:21:6: note: ‘main()::<lambda(Test&)>’ is not derived from ‘std::function<Ret(Test&)>’
[build] 21 | });```
通过删除 std::function
并将函数参数设为模板参数,这很容易解决。那看起来像
template<typename Func>
auto DoLocked(Func func) -> decltype(func(*this)) {
std::lock_guard<std::mutex> lock(*mtx);
return func(*this);
}
它不适用于 std::function
的原因是 lambda 表达式不会创建 std::function
。它创建一个未命名的 class 类型的对象,该对象具有用 lambda 表达式的主体定义的 operator()
。因此,模板推导失败,因为它期望 std::function
但这不是所提供的。
I want to accept any lambda, so that it can perform some operation safely under the lock_guard
这是完全错误的假设,会导致死锁。
锁是为了保护某些特定数据的一致性。
这些数据通常是一些单个 class.
的字段
现在关键部分应该保护这些数据并且不能调用任何任意代码。为什么?由于任意代码可以包含其他关键部分。这意味着您无法控制获取的锁的顺序。因此,对代码进行微小的无关更改将导致难以消除死锁。
我想接受任何 lambda,以便它可以在 lock_guard
下安全地执行一些操作,然后 return 任何东西,但是如下所示使用会引发错误:
#include <iostream>
#include <functional>
#include <mutex>
#include <memory>
class Test {
public:
template<typename Ret>
Ret DoLocked(std::function<Ret(Test&)> func) {
std::lock_guard<std::mutex> lock(*mtx);
return func(*this);
}
private:
std::unique_ptr<std::mutex> mtx = std::make_unique<std::mutex>();
};
int main() {
Test a;
a.DoLocked([](Test &s) {
std::cout << "in do locked" << std::endl;
});
return 0;
}
[build] /some-path/test.cc:21:6: error: no matching function for call to ‘Test::DoLocked(main()::<lambda(Test&)>)’
[build] 21 | });
[build] | ^
[build] /some-path/test.cc:9:13: note: candidate: ‘template<class Ret> Ret Test::DoLocked(std::function<Ret(Test&)>)’
[build] 9 | Ret DoLocked(std::function<Ret(Test&)> func) {
[build] | ^~~~~~~~
[build] /some-path/test.cc:9:13: note: template argument deduction/substitution failed:
[build] /some-path/test.cc:21:6: note: ‘main()::<lambda(Test&)>’ is not derived from ‘std::function<Ret(Test&)>’
[build] 21 | });```
通过删除 std::function
并将函数参数设为模板参数,这很容易解决。那看起来像
template<typename Func>
auto DoLocked(Func func) -> decltype(func(*this)) {
std::lock_guard<std::mutex> lock(*mtx);
return func(*this);
}
它不适用于 std::function
的原因是 lambda 表达式不会创建 std::function
。它创建一个未命名的 class 类型的对象,该对象具有用 lambda 表达式的主体定义的 operator()
。因此,模板推导失败,因为它期望 std::function
但这不是所提供的。
I want to accept any lambda, so that it can perform some operation safely under the lock_guard
这是完全错误的假设,会导致死锁。
锁是为了保护某些特定数据的一致性。 这些数据通常是一些单个 class.
的字段现在关键部分应该保护这些数据并且不能调用任何任意代码。为什么?由于任意代码可以包含其他关键部分。这意味着您无法控制获取的锁的顺序。因此,对代码进行微小的无关更改将导致难以消除死锁。