锁定的互斥锁是否保护condition_variable和数据?
Does a locked mutex protect the condition_variable as well as the data?
考虑以下 this_thread::sleep_for(( 函数的实现。它来自斯特劳斯特鲁普的书,"CPL",4,第1232页。我通过 (i( 重命名它和 (ii( 将函数与客户端代码分离来修改它:
#include <chrono> /// milliseconds
#include <mutex> /// mutex, unique_lock
#include <condition_variable> /// condition_variable
/// declarations ...
namespace ext
{
void sleep_for(int ms);
}
/// implementation ...
void ext::sleep_for(int ms)
{
std::mutex mtx;
std::condition_variable timercv;
/// acquire mtx
std::unique_lock<std::mutex> lck {mtx};
/// release and reacquire mutex
timercv.wait_for(lck, std::chrono::milliseconds {ms});
} // implicitly release mtx
斯特劳斯特鲁普说:
互斥锁保护wait_for((免受数据争用的影响。wait_for(( 在进入睡眠状态时释放其互斥锁,并在线程解锁时重新获取互斥锁。
我想问:
1(通过说mutex
保护wait_for()
免受数据竞争,我认为Stroustrup指的是condition_variable
本身,对吧?
2( 为什么condition_variable
需要并发访问保护?它是一个局部变量,而不是全局变量。线程对ext::sleep_for()
函数的每次调用都将具有condition_variable
的单独副本。
3(在此程序中,没有要保护的全局数据(例如就绪标志等(mutex
能保护condition_variable
吗?如果是这样,从什么?正如我所说,调用此函数的每个线程都将访问一个单独的副本。
-- 编辑 --
这是我对为什么在此代码中使用mutex
和condition_variable
的解释:
1(需要mutex
才能获得对它的锁定。
2(condition_variable
释放互斥锁上的锁,进入睡眠状态指定的时间段,然后重新获取锁。
代码中存在错误。允许条件变量虚假唤醒;您有责任处理该情况。 上面的代码中没有任何内容可以处理它。 这里有一个简单的解决方法:
timercv.wait_for(lck, std::chrono::milliseconds {ms}, []{return false;});
现在,任何早起都将被拒绝。
这仍然是条件变量的一个极其奇怪的用法。 通常它们用于在一个或多个线程之间进行通信。 在这种情况下,互斥锁和条件变量以及条件变量检查的事物形成三元组。
Stroustrup似乎在谈论一个更典型的案例。
在这种更典型的情况下,互斥锁保护对条件变量检查的事物的访问,并且必须锁定才能对条件变量执行某些操作。 由于这些是低级线程原语,您应该遵循有效的标准模式,或者您必须确切地了解每个操作的作用以及它提供的保证并证明您的代码是正确的。 任何简化都将以"告诉孩子谎言"的形式出现,并且基于谎言设计新的使用模式将没有任何可靠性。
确切的规格在标准中描述,这些是您应该参考的规格。 请注意,规格在标准修订版之间发生了变化。
简而言之,您应该找到经过验证的使用模式并使用它们,然后封装它们,永远不要碰它们。
编写睡眠的一个更简单的方法是:
void ext::sleep_for(int ms) {
std::mutex mtx;
std::unique_lock<std::mutex> lock1(mtx);
std::unique_lock<std::mutex> lock2(mtx, std::defer_lock_t{});
lock2.try_lock_for(std::chrono::milliseconds {ms});
} // implicitly release mtx
它没有那么复杂的一组条件,并且使用更简单的基元。
- 防止主数据类型C++的隐式转换
- 用于访问容器<T>数据成员的正确 API
- 嵌套在类中时无法设置成员数据
- 使用流处理接收到的数据
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- C++ Singleton - Prevent ::instance() to variable
- 在cuda线程之间共享大量常量数据
- C++将文本文件中的数据读取到结构数组中
- 如何在C++中序列化结构数据
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 通过套接字[TCP]传输数据 如何在C / C ++中打包多个整数并使用send() recv()传输数据
- 在c代码之间共享数据的最佳方式
- 链表,反向函数,数据结构
- 数据成员SFINAE的C++17测试:gcc vs clang
- C++浮点数据类型和字符串数据类型无法子到模板函数中
- 如何对点云数据进行排序
- 从矢量<无符号字符>转换为字符* 包括垃圾数据
- 尝试通过OCI例程从Oracle获取blob数据,但出现错误:ORA-01008:并非所有变量都绑定
- Cuda C++:设备上的Malloc类,并用来自主机的数据填充它