通过私有互斥锁锁定对象的最佳方法是什么
What is the best way to lock object by private mutex?
我需要在某些外部函数中通过私有互斥锁锁定对象。最好的方法是什么?
我想要这样的东西
#include <thread>
#include <mutex>
class Test
{
public:
std::lock_guard<std::mutex> lockGuard()
{
return std::lock_guard<std::mutex>(mutex);
}
private:
std::mutex mutex;
};
int main()
{
Test test;
std::lock_guard<std::mutex> lock = test.lockGuard();
//...
}
但是lock_guard
复制构造器被删除。我怎么能做这样的事情?
只需改用std::unique_lock<std::mutex>
。 它不可复制,但它是可移动的,允许你显示图案。
#include <thread>
#include <mutex>
class Test
{
public:
std::unique_lock<std::mutex> lockGuard()
{
return std::unique_lock<std::mutex>(mutex);
}
private:
std::mutex mutex;
};
int main()
{
Test test;
std::unique_lock<std::mutex> lock = test.lockGuard();
//...
}
std::unique_lock<std::mutex>
具有相对于std::lock_guard
的扩展 API,包括:
- 移动可构造。
- 移动可分配。
- 可交换。
- 锁()
- 解锁()
- try_lock()
- try_lock_for()
- try_lock_until()
- 发布()
- owns_lock()
换句话说,由于您可以解锁并从unique_lock
移动,因此不能保证将锁在互斥锁上(您可以检查它是否与owns_lock()
有关)。 相反,lock_guard
的不变性是它始终保持互斥锁的锁。
std::unique_lock<T>
定义了移动构造函数,可以随心所欲地使用,但该方法本身并不是很成功。您应该查看锁定粒度,通常,如果无法提供内部同步并要求用户在对对象执行操作时(或需要执行多个操作时)保持锁定,则没有理由将互斥锁存储在对象中。
如果我必须将互斥锁存储在对象内部,我会使用一些包装器,它允许我执行以下操作:
locking_wrapper<Test> test;
test.do_locked([] (Test & instance) {
/* The following code is guaranteed not to interleave with
* any operations performed on instance from other threads. */
// your code using instance here
});
locking_wrapper<T>
将存储对象的实例存储在其中,并提供对它的引用,同时保持内部互斥锁的锁。依靠编译器的内联代码能力,这种方法应该不会超出您在问题中尝试执行的操作的开销。
实施locking_wrapper
的总体思路如下:
template<typename T>
class locking_wrapper
{
mutable std::mutex mutex;
// the object which requires external synchronization on access
T instance;
public:
/* Here we define whatever constructors required to construct the
* locking_wrapper (e.g. value-initialize the instance, take an
* instance passed by user or something different) */
locking_wrapper() = default;
locking_wrapper(const T & instance) : instance{instance} {}
// Takes a functor to be performed on instance while maintaining lock
template<typename Functor>
void do_locked(Functor && f) const {
const std::lock_guard<std::mutex> lock{mutex};
f(instance);
}
};
您可以根据需要将任何可调用实体传递给do_locked
,但是像我之前建议的那样使用 lambda 表达式调用它将为它提供最好的机会,使其没有任何开销。
请注意,将这种方法与引用、可移动对象或我尚未预见到的其他类型一起使用需要对代码进行一些修改。
相关文章:
- 复制包含C++所有元素的对象!(构造函数和赋值,最佳实践?
- 处理影响跨不同线程共享对象的定时回调的最佳方法是什么?
- 将FFMpeg AVFrame对象从C++应用程序流式传输到Python的最佳方法?
- 使用 gtest 框架在单元测试代码中检查目标对象的私有变量的最佳实践是什么?
- 保留计时器集合(对象与指针)的最佳方法
- 将(临时的?)std::string传递给使用它来构造一个接受副本的对象的函数的最佳方法是什么?
- 从类中的对象调用类中的函数的最佳方法
- 这是使用构造函数初始化数组对象的最佳方法吗?
- 在 c++ 中重置大型对象实例的最佳方法是什么
- 将对象附加到智能指针向量的最佳方法
- 将对象数组作为参数传递的最佳方法是什么
- 如何为对象提供不同的接口(最佳)
- 调用列表中子对象方法的最佳方法
- 哪种数据结构是在一个向量中搜索和计数对象对的最佳数据结构
- 找到多组对象的最佳匹配的算法
- C++拥有持久对象的最佳方式
- 动态创建新对象的最佳方法
- 用C++编写返回对象的函数的最佳方法是什么
- 两者之间的最佳方法是什么:实例化对象或使用指针
- 确定两个文件路径引用同一文件对象的最佳方法是什么