1

我在多线程中遇到了一个问题,多线程模型是 1 Producer - N Consumer。

Producer 生成数据(每个字符数据大约 200 字节),将其放入固定大小的缓存中(即 2Mil)。数据与所有线程无关。它应用过滤器(已配置)并确定没有线程符合生成的数据。

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

问题:由于只有指向数据的指针提供给多个线程,当缓存变满时,Produces 想要删除第一项(旧项)。任何线程仍然引用数据的可能性。

可行的方式:使用原子粒度,当生产者确定符合条件的线程数时,它可以更新计数器和线程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; }
};

查切大师

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

当生产者删除它检查计数器的元素时,它大于 0,它会发送动作以释放对 m_in_use_threads 集中线程的引用。

问题

  1. 如果主缓存中有 2Mil 记录,则 InUseCounter 的数量将相等,因此 Mutex 变量,是否建议在单个进程中拥有 2Mil 互斥变量。
  2. 拥有大的单一数据结构来维护 InUseCounter 将导致更多的锁定时间来查找和减少
  3. 什么是我查找引用的最佳替代方法,以及谁拥有这些引用并且锁定时间非常短。

提前感谢您的建议。

4

3 回答 3

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

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

于 2012-01-10T08:40:18.813 回答
1

由于您已经有一个Producer->Consumer队列,一个非常简单的系统包括一个“反馈”队列(Consumer->Producer)。

在消费了一个项目之后,消费者将指针反馈给生产者,以便生产者可以删除该项目并更新缓存的“空闲列表”。

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

于 2012-01-10T08:42:39.753 回答
0
  1. 是的,2000000 个互斥锁是多余的。
  2. 1 个大结构将被锁定更长的时间,但需要更少的锁定/解锁。
  3. 最好的方法是使用 shared_ptr 智能指针:它们似乎是为此量身定制的。你自己不检查计数器,你只是清理你的指针。shared_ptr 是线程安全的,不是它指向的数据,但对于 1 个生产者(作者)/ N 个消费者(读者)来说,这应该不是问题。
于 2012-01-10T08:32:08.297 回答