2012-01-10 55 views
1

我遇到了多线程中的问题,多线程模型是1个生产者 - N个消费者。多线程中对数据的引用跟踪(多少/谁)

生产者所产生的数据(字符数据周围200bytes每个),把它在固定大小的高速缓存(即2密耳)。数据与所有线程无关。它应用过滤器(已配置)并确定线程数量是否符合生成的数据。

生产者推动指针数据分成合格的线程队列(仅指向数据的指针,以避免数据复制)。线程将deque并通过TCP/IP发送给它们的客户端。

问题:因为只有指针数据被提供给多个线程,当高速缓存变满,主要生产要删除的第一个项目(旧)。任何线程仍然可能引用数据。

可行之路:用原子粒度,当制片人决定了排位赛的线程数,它可以更新计数器和线程ID列表。

class InUseCounter 
{ 
    int   m_count; 
    set<thread_t> m_in_use_threads; 
    Mutex   m_mutex; 
    Condition  m_cond; 

public: 
    // This constructor used by Producer 
    InUseCounter(int count, set<thread_t> tlist) 
    { 
     m_count   = count; 
     m_in_use_threads = tlist; 
    } 

    // This function is called by each threads 
    // When they are done with the data, 
    // Informing that I no longer use the reference to the data. 
    void decrement(thread_t tid) 
    { 
     Gaurd<Mutex> lock(m_mutex); 
     --m_count; 
     m_in_use_threads.erease(tid); 
    } 

    int get_count() const { return m_count; } 
}; 

主chache

map<seqnum, Data> 
       | 
       v 
      pair<CharData, InUseCounter> 

当生产者将删除它检查计数器的元件,为大于0时,它发送动作以释放设置m_in_use_threads参考到螺纹上。

问题

  1. 如果在主缓存2MIL记录,将有相等数量 的InUseCounter,所以互斥可变因素,在一个单一的过程中这个建议有2MIL互斥varible。
  2. 有大单数据结构来保持InUseCounter将 造成更多的锁定时间去寻找和减少
  3. 什么是对我的方法的最佳替代品,以找出引用和谁 都非常少引用锁定时间。

提前感谢您的建议。

回答

4
  1. 200万个互斥体是有点多。即使它们是轻量级锁,它们仍然占用一些开销。
  2. InUseCounter放在一个单一结构中会导致线程在释放记录时引起争用;如果线程没有以锁步方式执行,这可能可以忽略不计。如果他们频繁发布记录并且争用率上升,这显然是一个表现下沉。
  3. 您可以通过让一个线程负责维护记录引用计数(生产者线程)并使其他线程通过单独的队列发回记录发布事件来提高性能,实际上,将生产者转换为记录发布事件使用者。当你需要刷新一个条目时,首先处理所有发布队列,然后运行你的发布逻辑。您将需要处理一些延迟,因为您现在正在排队发布事件,而不是立即尝试处理它们,但性能应该会更好。

顺便提一句,这与Disruptor框架的工作方式类似。这是高频率交易的高性能Java(!)并发框架。是的,我在同一句话中说过高性能的Java和并发性。对高性能并发设计和实现有很多有价值的见解。

+0

啊,同样的想法:)简洁的参考! – 2012-01-10 08:43:45

0
  1. 是的,200万互斥是矫枉过正。
  2. 1大结构将被锁定更长时间,但将需要更少的锁定/解锁。
  3. 最好的方法是使用shared_ptr智能指针:它们似乎是为此量身定制的。你不要自己检查柜台,你只需清理指针。 shared_ptr是线程安全的,而不是它指向的数据,但对于1个生产者(作家)/ N个消费者(读者)来说,这不应该是一个问题。
+0

我们认为shared_ptr <>支持。这种方法的问题在于,如果消费者长期持有该参考。内存峰值可能会发生,生产者也会失去对数据破坏的控制。这可能适用于一小部分数据,对象的生命周期非常短。 – naveenhegde 2012-01-10 09:40:03

+0

@naveen:只要需要,消费者应该持有参考。如果数据在消费者仍在使用时被破坏,则会发生不好的事情。如果消费者在参考完成后仍然坚持参考,这是一个糟糕的消费者(并且它也不会设置参考计数) – stefaanv 2012-01-10 10:47:34

1

由于您已有一个Producer->Consumer队列,因此一个非常简单的系统就是拥有一个“反馈”队列(Consumer->Producer)。

消费完一个项目后,消费者将指针返回给生产者,以便生产者可以删除该项目并更新缓存的“自由列表”。

这样,只有生产者触及缓存内部,不需要同步:只有队列需要同步。