首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >包含大量共享变量的C++标准条件变量

包含大量共享变量的C++标准条件变量
EN

Stack Overflow用户
提问于 2013-03-22 05:52:49
回答 3查看 1.3K关注 0票数 0

我正在用C++编写一个多线程程序,在我的主线程中,我在等待其他线程将包放入不同的队列中。这取决于包的类型和它们来自哪个线程。

队列受到互斥锁的保护,这是理所当然的。

但我主要不想做的事情是:

代码语言:javascript
复制
while(true)
if(!queue1->empty)
{
     do stuff
}
if(!queue2->empty)
{
     do stuff
}
etc

因此,您需要使用条件变量来通知main发生了一些变化。现在我只能阻塞一个条件变量,所以我需要所有这些线程使用相同的条件变量和一个伴随的互斥量。现在我并不想真正使用这个互斥锁来锁定我所有的线程。这并不意味着当一个线程写入队列时,另一个线程不能写入完全不同的队列。因此,我对每个队列使用单独的互斥锁。但是现在我该如何使用条件变量附带的这个额外的互斥锁呢?

它是如何使用boost用2个线程和1个队列来完成的,非常类似于std。http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html

代码语言:javascript
复制
template<typename Data>
class concurrent_queue
{
    private:
    boost::condition_variable the_condition_variable;  
    public:
    void wait_for_data()
    {
        boost::mutex::scoped_lock lock(the_mutex);
        while(the_queue.empty())
        {
             the_condition_variable.wait(lock);
        }
    }
    void push(Data const& data)
    {
         boost::mutex::scoped_lock lock(the_mutex);
         bool const was_empty=the_queue.empty();
         the_queue.push(data);
         if(was_empty)
         {
             the_condition_variable.notify_one();
         }
     }
     // rest as before
 };

那么你怎么解决这个问题呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-03-22 07:27:37

我想说你问题的关键在这里:

Now I dont want to really use this mutex to lock all my threads. It doesn't mean that when 1 thread is writing to a queue, another cant write to a totally different queue. So I use seperate mutexes for each queue.

为什么?因为:

... packages come in relatively slow. And queues are empty most of the time

在我看来,你把自己设计到了一个角落,因为你认为你需要的东西,而实际上你可能并不需要它,因为一个队列实际上可以在你提到的使用场景中工作。

我会说从一个队列开始,看看它能让你走多远。然后,当你遇到一个限制,你确实有许多线程在一个互斥锁上等待,你将有更多关于这个问题的信息,因此将能够更好地解决它。

从本质上讲,我会说你面临这个问题的原因是过早的设计优化,解决这个问题的方法是现在就回溯并更改设计。

票数 3
EN

Stack Overflow用户

发布于 2013-03-22 06:04:47

创建一个顶级(可能是循环的)队列,其中包含所有在其中有工作的队列。

这个队列可以由一个互斥锁来保护,并且有一个condvar,当它从空变为非空时,只需要用信号通知它。

现在,您的各个队列都可以有自己的互斥锁,当它们从空变为非空时,它们只需要接触共享/顶级队列(及其互斥锁)。

一些细节将取决于您是否希望您的线程依次从每个非空队列中获取前面的项,还是按顺序使用每个完整的队列,但想法是存在的。

从非空到非空(但增加了大小)的

也应该传递到顶级队列吗?

正如我所说的,这取决于你如何消费它们。如果,每次队列中有内容时,您都会这样做:

  1. (您已经拥有顶级锁,因此您知道此队列中有某些内容)
  2. 锁定队列
  3. 使用本地工作副本交换队列内容
  4. 从顶级队列中删除队列
  5. 解锁队列

则工作队列总是非空的,因此在顶层队列中,或者是空的,因此不在队列中。

如果您不这样做,而只是从每个非空队列中拉出前面的元素,那么您需要考虑更多的状态。

请注意,如果

...包的速度相对较慢。而且大多数时候队列都是空的

您可能只有一个队列,因为不会有足够的活动来引起大量的争用。这极大地简化了事情。

票数 2
EN

Stack Overflow用户

发布于 2013-03-26 10:50:36

“Carleeto”和“无用”都给出了很好的答案。您只有一个消费者,因此单个队列将为您提供最佳性能。您无法获得比单个使用者持续工作更高的吞吐量,因此您的目标应该是最小化单个使用者的锁定开销,而不是生产者的锁定开销。这是通过让生产者等待具有单个互斥锁的单个条件变量(指示队列不为空)来实现的。

下面是如何实现参数多态性的方法。完全的类型安全,没有强制转换,在父类中只有一个虚函数:

代码语言:javascript
复制
class ParentType {
public:
  virtual void do_work(...[params]...)=0;
  virtual ~ParentType() {}
};

class ChildType1 : public ParentType {
private:
  // all my private variables and functions
public:
  virtual void do_work(...[params]...) {
    // call private functions and use private variables from ChildType1
  }
};

class ChildType2: public ParentType {
private:
  // completely different private variables and functions
public:
  virtual void do-work(...[params]...) {
    // call private functions and use private variables from ChildType2
  }
};
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15558902

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档