C++ std::mutex 与 const函数

本文探讨了在C++中如何正确地使用std::mutex与std::lock_guard,并揭示了一个常见陷阱:在const成员函数中尝试锁定成员变量级别的std::mutex会引发编译错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 写一个队列需要在其函数之间做同步,首选了std::lock_guard通过RAII的方式来优雅实现确保释放。code很简单,Class自己有一个成员变量mutex, 相关函数在调用前使用其作为构造参数来构造lock_guard即可。
  2. 编译时遇到了问题,死活编译不过,有了这样的报错: note: candidate constructor not viable: 1st argument (‘const std::mutex’) would lose const qualifier. 初看百思不得其解,一度怀疑是不是lock_guard不支持成员变量级的mutex(当稍微想想也不可能,C++如果真做成这样,从使用性上讲就太糟糕了)。后来才发现,使用该mutex的函数全部都是const函数,去掉const以后编译正常。
  3. 这个时候才隐约想起在很久以前搞C++的时候,成员变量级的mutex是不能在const函数中lock的(因为lock是会引起改变的)。直接试了下mutex.lock(),IDE果然直接报错了。但是lock_guard却没有提示,看样子AS的code check还需要进一步提高。
  4. 又捡起了一个C++知识。
C++ 中,`std::mutex` 是一种用于线程同步的原始类型,它提供了互斥锁的功能。然而,`std::mutex` 的拷贝构造函数(copy constructor)是被删除的(deleted),这意味着不能通过拷贝来创建一个新的 `std::mutex` 对象。当尝试拷贝一个 `std::mutex` 对象时,编译器会报错,指出使用了已删除的函数 `std::mutex::mutex(const std::mutex&)`。这一设计决定是为了防止在多线程环境中出现未定义行为[^3]。 具体来说,`std::mutex` 的拷贝构造函数被删除的原因在于互斥锁本质上是不可复制的资源。互斥锁的状态(是否被锁定)是特定的 `std::mutex` 实例紧密相关的。如果允许拷贝互斥锁,那么拷贝后的对象应该如何反映原对象的状态就成了一个问题。例如,如果原互斥锁处于锁定状态,拷贝后的互斥锁是否也应该被视为锁定?如果是这样,那么解锁其中一个互斥锁时,另一个互斥锁的状态又该如何处理?这些问题都没有一个明确且安全的解决方案。 此外,从设计的角度来看,互斥锁通常用于保护某些特定的数据结构或代码段,它们的生命周期和作用域应当被仔细管理。允许拷贝互斥锁可能会导致意外的共享和访问模式,从而增加死锁的风险或者导致其他并发问题。因此,为了确保程序的正确性和可维护性,C++ 标准库的设计者选择了禁止互斥锁的拷贝构造。 解决这个问题的方法通常是避免直接拷贝 `std::mutex` 对象。如果需要在多个地方使用同一个互斥锁,可以通过引用或指针传递已存在的 `std::mutex` 对象。另外,如果确实需要多个互斥锁实例,应该显式地为每个需要保护的资源创建独立的 `std::mutex` 对象。 下面是一个简单的例子,展示了如何正确地使用 `std::mutex` 来保护共享数据: ```cpp #include <iostream> #include <mutex> #include <thread> std::mutex mtx; // 全局互斥锁 void print_block(int n, char c) { // 锁定互斥锁 std::lock_guard<std::mutex> lock(mtx); for (int i = 0; i < n; ++i) { std::cout << c; } std::cout << '\n'; } int main() { std::thread th1(print_block, 50, '*'); std::thread th2(print_block, 50, '$'); th1.join(); th2.join(); return 0; } ``` 在这个例子中,`std::mutex` 被声明为全局变量,并且通过引用传递给 `std::lock_guard`,后者负责在构造时锁定互斥锁并在析构时自动解锁互斥锁。这种方式避免了直接拷贝 `std::mutex` 对象的需求,同时也确保了互斥锁的正确使用[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值