【发布时间】:2018-05-12 16:22:56
【问题描述】:
考虑以下this_thread::sleep_for() 函数的实现。它来自 Stroustrup 的书 "CPL", 4, pg 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
Stroustrup 表示:
互斥锁保护 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 释放互斥锁上的锁,进入休眠指定时间,然后重新获取锁。
【问题讨论】:
-
您的代码出错,我不知道是不是因为源代码中的转录器(有时 Stroustrup 使用的是准标准 C++)。
wait_for应该传递第三个参数[]{return false;}来修复它。 -
@Yakk-AdamNevraumont 不,谓词是可选的,有一个重载,只需要一个锁和一个时间。
-
你是对的。这是一个不好的例子。您对本地 cv 和互斥锁是正确的。没有全局数据意味着没有什么可以用锁来保护的。此外,正如@Yakk-AdamNevraumont 所说,它缺少一个谓词来保护它免受虚假唤醒。 (时间为MAX时间,但允许更小)。也许有一些奇怪的用例,但我不知道。条件变量的原始用例是允许持有互斥锁的线程休眠(也称为块)并以原子方式释放互斥锁。然后稍后以原子方式唤醒并重新获取互斥体。
-
@Yakk,我已经编辑了帖子以添加一个可能的解释,说明为什么在此代码中使用
mutex和condition_variable。 -
@ssteven 我理解代码;问题是代码有错误。
标签: c++ multithreading