在操作系统的进程同步中,条件变量的原理是什么?
当我试图用另一个线程唤醒一个线程时,我遇到了一个问题.简单的生产者/消费者的事物.
代码下方.第85行是我不明白的原因,为什么它不起作用.生产者线程填充std :: queue并在消费者线程等待NOT std :: queue.empty()时调用std :: condition_variable.notify_one().
在此先感谢您的帮助
#include <mutex>
#include <condition_variable>
#include <queue>
#include <string>
#include <iostream>
#include <thread>
// request
class request :
public std::mutex,
public std::condition_variable,
public std::queue<std::string>
{
public:
virtual ~request();
};
request::~request()
{
}
// producer
class producer
{
public:
producer(request &);
virtual ~producer();
void operator()();
private:
request & request_;
};
producer::producer(request & _request)
:
request_(_request)
{
}
producer::~producer()
{
}
void
producer::operator()()
{
while (true) {
std::lock_guard<std::mutex> lock(request_);
std::cout << "producer\n";
request_.push("something"); …Run Code Online (Sandbox Code Playgroud) 当实施条件变量成一个Win32 C++程序,这将是最好使用Win32函数,类,和数据类型(例如CreateThread,SleepConditionVariableCS,WaitForSingleObjectEx,ReleaseMutex,CONDITION_VARIABLE),或那些来自C++ 11标准库(例如thread,wait,join,unlock,condition_variable)?
由于这个问题的答案可能不是二元的,在做出这样的决定时应该考虑哪些因素?
假设有三个线程A,B和C.B和C在某一点暂停,等待A发信号通知它们继续.在标准C++提供的线程同步工具中,std::condition_variable似乎最适合这里(尽管仍然很糟糕).由于std::condition_variable必须与锁一起使用,因此B和C的代码可能包含以下行:
{
std::mutex mut;
std::unique_lock<std::mutex> lock(mut);
cond_var.wait(lock); // cond_var is a global variable of type std::condition_variable`
}
Run Code Online (Sandbox Code Playgroud)
注意,mut这里使用的不是用于同步目的,而只是为了符合签名std::condition_variable::wait.有了这个观察,我想也许我们可以通过实现虚拟锁类来做得更好,比方说dummy_lock,并替换std::condition_variable为std::condition_variable_any.dummy_lock符合BasicLockable要求,其所有方法基本上什么都不做.因此,我们得到类似于以下代码:
{
dummy_lock lock;
cond_var.wait(lock); // cond_var is a global variable of type std::condition_variable_any`
}
Run Code Online (Sandbox Code Playgroud)
如果可以的话,这应该比原来的效率更高.但问题是,它是否按照标准运作(语言律师在这里适用)?即使它有效,这绝不是一个优雅的解决方案.那么,你们中的任何人都有更好的想法吗?
c++ multithreading locking condition-variable language-lawyer
如果std::condition_variable由于虚假的唤醒可以发出信号(我们无法确定我们需要的条件是否真的满足),为什么C++标准库提供wait()没有谓词的方法的重载?可以使用此类行为的情况是什么?
我正在使用这样的std::condition_variable结合std::unique_lock。
std::mutex a_mutex;
std::condition_variable a_condition_variable;
std::unique_lock<std::mutex> a_lock(a_mutex);
a_condition_variable.wait(a_lock, [this] {return something;});
//Do something
a_lock.unlock();
Run Code Online (Sandbox Code Playgroud)
工作正常。据我了解,std::condition_variable接受std::unique_lock它等待。但是,我正在尝试将其与std::lock_guard但不能结合在一起。
我的问题是: 可以std::unique_lock用a std::lock_guard代替吗?这样可以避免我每次使用锁时都手动解锁。
#include <iostream>
#include <thread>
#include <condition_variable>
#include <queue>
#include <cstdlib>
#include <chrono>
#include <ctime>
#include <random>
using namespace std;
//counts every number that is added to the queue
static long long producer_count = 0;
//counts every number that is taken out of the queue
static long long consumer_count = 0;
void generateNumbers(queue<int> & numbers, condition_variable & cv, mutex & m, bool & workdone){
while(!workdone) {
unique_lock<std::mutex> lk(m);
int rndNum = rand() % 100;
numbers.push(rndNum);
producer_count++;
cv.notify_one();
}
}
void work(queue<int> …Run Code Online (Sandbox Code Playgroud) 我的程序通过使用空闲的工作线程将多行文本打印到控制台。然而,问题是工作线程在打印文本之前没有等待前一个工作线程完成,这导致文本被插入到另一个工作线程的文本中,如下图所示:
我需要通过使用 std::condition_variable 来解决这个问题——称为忙等待问题。我已经尝试在下面的代码中实现 condition_variable,基于在这个链接上找到的例子,下面的 stackoverflow 问题对我有帮助,但还不够,因为我对 C++ 的一般知识有限。所以最后我只是把所有的东西都注释掉了,我现在不知所措。
// threadpool.cpp
// Compile with:
// g++ -std=c++11 -pthread threadpool.cpp -o threadpool
#include <thread>
#include <mutex>
#include <iostream>
#include <vector>
#include <deque>
class ThreadPool; // forward declare
//std::condition_variable cv;
//bool ready = false;
//bool processed = false;
class Worker {
public:
Worker(ThreadPool &s) : pool(s) { }
void operator()();
private:
ThreadPool &pool;
};
class ThreadPool {
public:
ThreadPool(size_t threads);
template<class F> void enqueue(F f);
~ThreadPool(); …Run Code Online (Sandbox Code Playgroud) 我在很多地方都读到过与std::condition_variable_any. 只是想知道,这是什么开销?
我的猜测是,由于这是一个可以与任何类型的锁一起使用的通用条件变量,因此它需要手动滚动实现等待(可能使用另一个 condition_variable 和 mutex 或 futex 或类似的东西),因此额外的开销可能来自那?但不确定......而不是仅仅作为本机包装器pthread_cond_wait()(和其他系统上的等价物)等。
作为后续,如果我说实现一些等待的东西,比如共享互斥锁,那么由于性能开销,这种类型的条件变量是一个糟糕的选择吗?在这种情况下我还能做什么?
我目前正在使用Asio C ++库,并围绕它编写了一个客户端包装。我最初的方法非常基础,只需要向一个方向传送即可。需求已更改,我已切换为使用所有异步调用。除了以外,大多数迁移都很容易asio::async_write(...)。我使用了几种不同的方法,每种方法不可避免地陷入僵局。
该应用程序连续大量传输数据。我没有使用多线程,因为它们不会阻塞,并且可能导致内存问题,尤其是在服务器负载沉重时。作业将备份,并且应用程序堆会无限期地增长。
因此,我创建了一个阻塞队列,只是为了找出在回调之间使用锁或阻塞事件导致未知行为的困难方法。
包装器是一个非常大的类,因此,我将尝试解释我的现状,并希望能得到一些好的建议:
asio::steady_timer按固定时间表运行的设备,可将心跳消息直接推入阻塞队列。例如,在队列中,我有一个queue::block()和queue::unblock(),它们只是条件变量/互斥锁的包装。
std::thread consumer([this]() {
std::string message_buffer;
while (queue.pop(message_buffer)) {
queue.stage_block();
asio::async_write(*socket, asio::buffer(message_buffer), std::bind(&networking::handle_write, this, std::placeholders::_1, std::placeholders::_2));
queue.block();
}
});
void networking::handle_write(const std::error_code& error, size_t bytes_transferred) {
queue.unblock();
}
Run Code Online (Sandbox Code Playgroud)
当套接字备份并且服务器由于当前负载而无法再接受数据时,队列将填满并导致死锁,handle_write(...)而永不调用该死锁。
另一种方法完全消除了使用者线程,并依赖于handle_write(...)弹出队列。像这样:
void networking::write(const std::string& data) {
if (!queue.closed()) {
std::stringstream stream_buffer;
stream_buffer << data << std::endl;
spdlog::get("console")->debug("pushing to queue {}", queue.size());
queue.push(stream_buffer.str()); …Run Code Online (Sandbox Code Playgroud)