2013-03-21 72 views
0

我在C++和我的主线程中编写多线程程序我正在等待其他线程将程序包放入不同的队列。取决于包的种类以及它们来自哪个线程。C++ std条件变量覆盖很多共享变量

队列受互斥体保护,因为它应该是。

但在我主我不想做:

while(true) 
if(!queue1->empty) 
{ 
    do stuff 
} 
if(!queue2->empty) 
{ 
    do stuff 
} 
etc 

所以你需要使用条件变量信号的主要事情有了变化。现在我只能阻塞1个条件变量,所以我需要所有这些线程使用相同的条件变量和伴随的互斥。现在我不想真正使用这个互斥锁来锁定我所有的线程。这并不意味着当1个线程写入队列时,另一个线程不能写入完全不同的队列。所以我为每个队列使用单独的互斥体。但是现在我该如何使用条件变量附带的这个额外的互斥锁。

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

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 
}; 

那么,你如何解决这个问题?

回答

3

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

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

在我看来,你已经设计成自己的,因为你以为你在需要的时候在现实中,你可能并不需要它,因为一个队列会在有实际工作的东西角落你提到的使用场景。

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

实质上,我想说你面临这个问题的原因是过早的设计优化,而解决这个问题的方法就是现在回溯和改变设计。

+0

一个队列的问题是程序包是不同类的对象。根据它们在不同线程中产生的类型,还需要在主线程中进行不同的处理。也主要制作包并将它们发送到线程。我正在通过串口与Zigbee通信。我有一个web服务运行,它接受HTTP包,并且我是一个web服务的客户端,它运行某种特殊的数据库,并将数据放入其中。 所以1队列不会工作,导致来自不同类别的数据包或对象。我不想整个演出。 (或者我应该怎么做?) – Silver 2013-03-22 13:41:22

+1

您可以将该类型编码为数字字段,这将消除铸造问题。 – Carl 2013-03-22 21:34:22

+0

Idd我可以做到这一点,但我并不觉得这样做完全舒服。如果不是必要的话,一般的经验法则不会过多。但我想在这种情况下可能有必要。 – Silver 2013-03-24 13:41:04

2

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

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

现在,您的个人队列可以每个人都有自己的互斥,而他们只需要触摸共享/顶级队列(和它的互斥体)时他们改变从空非空。

一些细节将取决于您是希望您的线程依次从每个非空队列中依次获取前端项目,还是依次占用每个整个队列,但这个想法就在那里。


从非空要非空(但增加的大小)也应传递到顶级队列?

如我所说,这取决于你如何消费它们。如果,每次一个队列有东西在里面,你这样做:

  1. (你已经拥有了顶级的锁,那你怎么知道这个队列中有东西在里面)
  2. 锁定队列
  3. 交换与本地工作副本
  4. 队列内容从顶层队列
  5. 解锁队列除去队列

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

如果你不要做到这一点,只要关闭每个非空队列的前端元素,那么你有更多的状态要考虑。


注意,如果

...包进来相对较慢。和队列为空的大部分时间

你很可能只是拥有一个队列,因为不会有足够的活动引起了很多争论。这极大地简化了事情。

+0

好的软件包进来相对较慢。大部分时间队列都是空的。所以每次包进来时,我仍然需要访问顶层队列。 此外,我不明白为什么只有当单个队列从空到非空时才能锁定顶层队列。从非空到非空(但增加大小)也应该传递到顶层队列? 我想我可能会将共享队列中的项目复制到我的主队列中的本地队列中。因为处理可能需要一些地方。所以清空队列将会相对较快。只需要queue.front()和queue.pop()。 – Silver 2013-03-21 22:32:23

+0

锁定所有队列不会让我的程序很糟糕,但它是论文的一部分,我想尽可能优化它。我可以只使用一个互斥体来锁定并用于我的条件变量,但不会锁定任何队列。或者你认为这会在某个地方造成问题吗? – Silver 2013-03-21 22:37:13

0

@Carleeto和@Useless都给出了很好的答案。你只有一个消费者,所以一个队列会给你最好的性能。无法获得比单个消费者持续工作更高的吞吐量,因此您的目标应该是尽量减少单个消费者的锁定开销,而不是生产者。您可以通过让生产者用单个互斥锁等待单个条件变量(指示该队列非空)来完成此操作。

下面是你如何做参数多态性。完整的类型安全性,不需要铸造,并且在父类中只有一个虚函数:

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 
    } 
};