简体   繁体   English

C ++ 11如何在1个线程中使用条件变量处理2个线程安全队列

[英]C++11 How to handle 2 thread safe queues using condition variables in 1 thread

I have 2 connection objects running on there own threads that each put different data into there respective queue that is running in the main thread. 我有2个连接对象在各自的线程上运行,每个线程将不同的数据放入各自在主线程中运行的队列。 So the main thread has 2 queues and needs to be awaken when either one of these queues signals it has put in data. 因此,主线程有2个队列,当其中一个队列发出信号已将其放入数据时,需要将其唤醒。 I have written a thread-safe queue that encapsulates pushing,popping and signaling the condition variable inside the theadsafe_queue. 我编写了一个线程安全队列,该队列在theadsafe_queue内封装了对条件变量的推送,弹出和信号传递。 But it seems as it won't work because in the main loop it can block inside the first queue and data can come to the second queue and not be waked up and vice versa. 但这似乎不起作用,因为在主循环中,它可能会阻塞第一个队列,而数据可能进入第二个队列,而不会被唤醒,反之亦然。
Do I have to shared the same condition variable and mutex between the 2 queues. 我是否必须在两个队列之间共享相同的条件变量和互斥量。 I could modify my threadsafe_queue to take the condition variable and mutex as parameters and pass the same ones to each queue. 我可以修改我的threadsafe_queue以将条件变量和互斥锁作为参数,并将相同的参数传递给每个队列。 Or I am thinking maybe using wait_until with a timer for each queue to give a chance to check each queue once there is a timeout, but this doesn't seem efficient. 或者我在想,也许对每个队列使用带有计时器的wait_until,以便一旦出现超时就可以检查每个队列,但这似乎并不高效。 The main processing thread has alot legacy code with static objects/variables and containers so it can't be split into 2 threads without introducing alot of locks. 主处理线程具有大量带有静态对象/变量和容器的遗留代码,因此在不引入大量锁的情况下无法将其拆分为2个线程。 What do you think is the best way. 您认为什么是最好的方法。

Merge the queues. 合并队列。

Or, write a streaming system. 或者,编写流系统。 The producers don't need to know where their data goes; 生产者不需要知道他们的数据在哪里。 it jist has to go. 它必须走。 They need a: 他们需要:

template<class T>
using sink=std::function<void(T)>;

to send their data. 发送他们的数据。

The listener doesn't need to know where the data is coming from. 侦听器不需要知道数据来自何处。 It needs a source: 它需要一个来源:

template<class T>
using source= sink<sink<T>>;

now they are on different threads; 现在它们处于不同的线程上; so you need a way to get data from A to B. 因此,您需要一种从A到B获取数据的方法。

template<class T>
struct threadsafe_queue {
  sink<T> get_sink();
  source<T> get_source();
};

in there maintain your mutex, condition variable, and buffer. 在其中维护您的互斥锁,条件变量和缓冲区。

Now here ismthe fun part. 现在,这是有趣的部分。 If we have X=variant<A,B> , then sink<X> can convert to sink<A> (also source<A> can convert to source<X> ). 如果我们有X=variant<A,B> ,则接收sink<X>可以转换为接收sink<A> (也可以将source<A>转换为source<X> )。

So if thread 1 produces A and thread 2 produces B , they can both feed into a sink<X> without them even knowing. 因此,如果线程1产生A且线程2产生B ,它们甚至都可以不知道就馈入接收sink<X>

Meanwhile the consumer thread sees either A or B coming from the queue. 同时,使用者线程看到AB来自队列。

You can replace source<T>=sink<sink<T>> with source<T>=std::function<std::optional<T>()> , where it returns empty when done. 您可以将source<T>=sink<sink<T>>替换为source<T>=std::function<std::optional<T>()> ,完成后返回空值。 I loke sources being sinks of sinks; 我认为源头是汇。 use is: 用途是:

void print_ints( source<int> src ) {
  src([](int x){ std::cout<<x<<','; });
  std::cout<<"\n";
}

vs my less preferred: 与我不那么喜欢:

void print_ints( source<int> src ) {
  while(auto x=src()){std::cout<<*x<<','; };
  std::cout<<"\n";
}

As an aside, you can tag source/sink types and overload | 顺便说一句,您可以标记源/接收器类型和重载| and add pipe<In,Out> etc. 并添加pipe<In,Out>等。

But that isn't useful here. 但这在这里没有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM