我正在学习C++ 11并发性,其中我以前唯一的并发原语经验是六年前的操作系统类,所以如果可以,请保持温和.
在C++ 11中,我们可以编写
std::mutex m;
std::condition_variable cv;
std::queue<int> q;
void producer_thread() {
std::unique_lock<std::mutex> lock(m);
q.push(42);
cv.notify_one();
}
void consumer_thread() {
std::unique_lock<std::mutex> lock(m);
while (q.empty()) {
cv.wait(lock);
}
q.pop();
}
Run Code Online (Sandbox Code Playgroud)
这样可以正常工作,但我觉得需要包裹cv.wait一个循环.我们需要循环的原因对我来说很清楚:
Consumer (inside wait()) Producer Vulture
release the lock
sleep until notified
acquire the lock
I MADE YOU A COOKIE
notify Consumer
release the lock
acquire the lock
NOM NOM NOM
release the lock
acquire the lock
return from wait()
HEY WHERE'S MY COOKIE I EATED IT
Run Code Online (Sandbox Code Playgroud)
现在,我相信其中一个很酷的事情 …
我正在尝试在C++ 11中实现一些跨平台代码.此代码的一部分使用std :: condition_variable实现信号量对象.当我需要在信号量上进行定时等待时,我使用wait_until或wait_for.
我遇到的问题是,似乎基于POSIX的系统上的 condition_variable的标准实现依赖于系统时钟,而不是单调时钟(另请参阅:针对POSIX规范的此问题)
这意味着如果系统时钟在过去的某个时间发生变化,我的条件变量将阻塞的时间比我预期的要长得多.例如,如果我希望我的condition_variable在1秒后超时,如果有人在等待期间将时钟调整回10分钟,则condition_variable会阻塞10分钟+ 1秒.我已经确认这是Ubuntu 14.04 LTS系统上的行为.
我需要依赖这个超时至少有些准确(即,在某些误差范围内它可能是不准确的,但如果系统时钟发生变化仍然需要执行).看起来我需要做的就是编写我自己的condition_variable版本,该版本使用POSIX函数并使用单调时钟实现相同的接口.
这听起来像很多工作 - 而且有点混乱.还有其他解决此问题的方法吗?
我正在使用C++ 11,我有一个std::thread类成员,它每2分钟向听众发送一次信息.其他它只是睡觉.所以,我让它睡了2分钟,然后发送所需的信息,然后再睡2分钟.
// MyClass.hpp
class MyClass {
~MyClass();
RunMyThread();
private:
std::thread my_thread;
std::atomic<bool> m_running;
}
MyClass::RunMyThread() {
my_thread = std::thread { [this, m_running] {
m_running = true;
while(m_running) {
std::this_thread::sleep_for(std::chrono::minutes(2));
SendStatusInfo(some_info);
}
}};
}
// Destructor
~MyClass::MyClass() {
m_running = false; // this wont work as the thread is sleeping. How to exit thread here?
}
Run Code Online (Sandbox Code Playgroud)
问题:
这种方法的问题是我无法在线程休眠时退出线程.我从阅读中理解,我可以使用a唤醒它std::condition_variable并优雅地退出?但我正在努力寻找一个简单的例子,它可以满足上述场景中的要求.condition_variable我发现的所有例子看起来都太复杂了,我想在这里做些什么.
问题:
如何std::condition_variable在睡眠时使用a 唤醒线程并正常退出?或者,没有这种condition_variable技术,还有其他方法可以实现相同的目标吗?
另外,我看到我需要std::mutex结合使用std::condition_variable?这真的有必要吗?通过将std::condition_variable逻辑仅添加到代码中的所需位置,是否无法实现目标? …
正如事实证明,condition_variable::wait_for的确可以称为condition_variable::wait_for_or_possibly_indefinitely_longer_than,因为它需要之前确实超时并返回到重新获取锁.
请参阅此程序以进行演示.
有没有办法表达,"看,我真的只有两秒钟.如果myPredicate()当时仍然是假的和/或锁仍然锁定,我不在乎,只是随身携带,并给我一个方法来检测那."
就像是:
bool myPredicate();
auto sec = std::chrono::seconds(1);
bool pred;
std::condition_variable::cv_status timedOut;
std::tie( pred, timedOut ) =
cv.really_wait_for_no_longer_than( lck, 2*sec, myPredicate );
if( lck.owns_lock() ) {
// Can use mutexed resource.
// ...
lck.unlock();
} else {
// Cannot use mutexed resource. Deal with it.
};
Run Code Online (Sandbox Code Playgroud) 我们正在使用Mac上的音频播放器项目,并注意到电源使用率非常高(约为google chrome执行相同工作负载的7倍).
我使用了xcode的能量分析工具,其中一个问题是我们有太多的CPU唤醒开销.
根据xcode:
每次CPU从空闲状态唤醒时,都会产生能量损失.如果唤醒很高,并且每次唤醒的CPU利用率很低,那么您应该考虑批处理工作.
我们已经将问题缩小到了一个usleep函数调用.
在我们的代码中,音频解码器是一个生产音频数据并将其插入消费者的生产者 - 音频播放器.我们的音频播放器基于OpenAL,它具有音频数据缓冲区.
因为音频播放器可能比生产者慢,所以我们总是在向音频播放器提供新的音频数据之前检查缓冲器的可用性.如果没有可用的缓冲区,我们会暂停一段时间再试一次.所以代码看起来像:
void playAudioBuffer(Data *data)
{
while(no buffer is available)
{
usleep()
}
process data.
}
Run Code Online (Sandbox Code Playgroud)
知道usleep是一个问题,我们做的第一件事就是删除usleep().(因为OpenAL似乎不提供回调或任何其他方式,轮询似乎是唯一的选择.)我们成功地将功耗降低了一半.
然后,昨天,我们尝试了
for(int i =0; i<attempts; ++i)
{
std::unique_lock<std::mutex> lk(m);
cv.wait_for(lk, 3, []{
available = checkBufferAvailable();
return available;
})
if (available)
{
process buf;
}
}
Run Code Online (Sandbox Code Playgroud)
这是我们偶然尝试的一项实验.它对我们来说没有任何意义,因为逻辑上它执行相同的等待.并且条件变量的使用不正确,因为变量"available"只能由一个线程访问.但它实际上减少了90%的能耗,线程的CPU使用量下降了很多.现在我们比铬更好.但条件变量如何实现与以下代码不同?为什么它会节省我们的力量?
mutex lock;
while(condition is false)
{
mutex unlock;
usleep();
mutex lock;
}
...
mutex unlock
...
Run Code Online (Sandbox Code Playgroud)
(我们使用mac的活动监视器(能量编号)和cpu使用情况分析工具来测量能耗.)
我在理解条件变量及其与互斥体的使用方面遇到了一些麻烦,我希望社区可以帮助我.请注意,我来自win32背景,所以我使用CRITICAL_SECTION,HANDLE,SetEvent,WaitForMultipleObject等.
这是我第一次使用c ++ 11标准库进行并发尝试,它是此处的程序示例的修改版本.
#include <condition_variable>
#include <mutex>
#include <algorithm>
#include <thread>
#include <queue>
#include <chrono>
#include <iostream>
int _tmain(int argc, _TCHAR* argv[])
{
std::queue<unsigned int> nNumbers;
std::mutex mtxQueue;
std::condition_variable cvQueue;
bool m_bQueueLocked = false;
std::mutex mtxQuit;
std::condition_variable cvQuit;
bool m_bQuit = false;
std::thread thrQuit(
[&]()
{
using namespace std;
this_thread::sleep_for(chrono::seconds(7));
// set event by setting the bool variable to true
// then notifying via the condition variable
m_bQuit = true;
cvQuit.notify_all();
}
);
std::thread thrProducer( …Run Code Online (Sandbox Code Playgroud) 我试图添加一个condition_variable来处理线程,但在这一行得到一个编译错误:
this->cv.wait(lk, []{return this->ready;});
Run Code Online (Sandbox Code Playgroud)
看起来像变量this-> ready,'this'不在合适的范围内.
在Java中,这可以通过TestThread来处理.这在C++中有什么相同的吗?
void TestThread::Thread_Activity()
{
std::cout << "Thread started \n";
// Wait until ThreadA() sends data
{
std::unique_lock<std::mutex> lk(m);
this->cv.wait(lk, []{return ready;});
}
std::cout << "Thread is processing data\n";
data += " after processing";
// Send data back to ThreadA through the condition variable
{
// std::lock_guard<std::mutex> lk(m);
processed = true;
// std::cout << "Thread B signals data processing completed\n";
}
}
Run Code Online (Sandbox Code Playgroud) 我正在浏览“原子操作库”,并遇到了原子“等待”和“notify_ ”方法的新 C++20 功能。我很好奇 std::condition_variable 的 'wait' 和 'notify_ ' 方法有何不同。
c++ ×9
c++11 ×4
mutex ×3
concurrency ×2
boost ×1
boost-thread ×1
c++20 ×1
energy ×1
pthreads ×1
scope ×1
semaphore ×1
stdatomic ×1
stdthread ×1
system-clock ×1
this ×1
thread-sleep ×1
time ×1