【问题标题】:Why the threads are not reused in the Thread Pool?为什么线程没有在线程池中重用?
【发布时间】:2022-01-10 18:42:16
【问题描述】:

我正在尝试在 C 中实现线程池模型,但线程本身存在问题。我创建了 10 个 pthread,并且我有一个包含它们需要处理的数据包的队列,但问题是,例如,当我有 100 个数据包时,线程仍然只处理前 10 个。所以,我猜他们只是在第一次使用后停止工作。处理完前一个数据包后,如何让线程重用?

这里是线程的创建:

for(i=0;i<10;i++){
        pthread_create(&t[i],NULL,func,args);
    }

然后,当我收到要使用的新数据包时,我会将其排入工作队列:

pthread_mutex_lock(&q_mux);
enqueue(queue,p);
pthread_cond_broadcast(&qcond);
pthread_mutex_unlock(&q_mux);

最后,我将队列中的第一个数据包取出来:

pthread_mutex_lock(&q_mux);
while(isempty(queue)){  
        pthread_cond_wait(&queue_cond,&q_mux);
}
p=queue->head->p;
dequeue(queue);
pthread_mutex_unlock(&q_mux);
process(p);

【问题讨论】:

  • 是的,您在问为什么有些代码不起作用,但您没有显示任何代码。见minimal reproducible example
  • @qwerty 发布了足够多的代码,以便有人可以将代码复制并粘贴到文本编辑器中,然后编译并运行它以查看问题是否发生。
  • 好吧,'while(1) processQueueItem();'似乎是个不错的计划。

标签: c multithreading pthreads threadpool


【解决方案1】:

假设:线程处理逻辑周围不存在“直到队列空循环”,线程在等待和处理单个项目后正常终止。

这与仅处理 10 个项目的行为相匹配,创建的 10 个线程中的每个线程都有 1 个项目。 pthread_create 只是启动一个新线程,线程在处理完成后不会自动重新启动。

考虑:

 // Loop until all items processed..
 while (!shutdown) {
     // take first packet and dequeue.. 99 packets of bits in the queue..
     pthread_mutex_lock(&q_mux);
     // ..
 }

当然,必须按照shutdown 的含义工作,并将其与(not) isempty 检查结合使用,以避免空队列出现死锁。

处理这种情况的一种方法是在所有要处理的项目之后排队一个“已完成”项目。当一个线程遇到这个项目时,它们将从每个线程内的主循环返回而终止。

// Inside a thread, loop indefinitely and consume from the
// queue until encountering an item that indicates processing
// should stop.
while (true) {
    pthread_mutex_lock(&q_mux);
    while (!shutdown & isempty(queue)) {  
        pthread_cond_wait(&queue_cond,&q_mux);
    }
    p=queue->head->p;
    if (p->is_finished) {
        // Run into 101'th item with special flag
        pthread_mutex_unlock(&q_mux);
        // signal other waiting threads (allows replacing broadcast with signal)
        pthread_cond_signal(&qcond);
        break;
    }   
    dequeue(queue);
    pthread_mutex_unlock(&q_mux);
    process(p);
}

在这种情况下,“已完成”项目不会出队,因此所有线程都可以看到它;另一种变体是为每个线程添加一个“已完成”项并允许它出列,这样当所有线程终止时队列完全耗尽。

另一种方法是对队列本身使用“添加完成”标志,并确保它也向互斥体发出信号。 (当队列被标记为“添加完成”时,它不能添加新项目。)

while (isempty(queue)) {
    if (isaddingcomplete(queue)) {
        // empty and nothing else can be added..
        pthread_mutex_unlock(&q_mux);
        // signal other waiting threads (allows replacing broadcast with signal)
        pthread_cond_signal(&qcond);
        return;
    }
    pthread_cond_wait(&queue_cond,&q_mux);
}

给地鼠换皮的方法有很多。

【讨论】:

  • 我是线程新手,但我认为线程池模型的主要原理是线程在完成任务后只会等待,当队列中有新数据包时,它会自动占用它。或者换句话说,线程在空闲时,总是试图从队列中获取一个新的数据包(并且当队列为空时才停止)。
  • @qwerty 线程从它们的身体返回时完成。没有任何标准会“重新运行”线程。虽然这似乎是线程池在特定队列处理上的一个概念的实现,但 pthreads_create 与线程池没有任何隐含关系,它只执行所要求的操作:它创建并启动一个新的线程。
  • @qwerty, Re, “我认为...[the] 线程...只会...”您创建的线程永远不会做任何事情,除非执行 为其提供的代码。如果您提供的代码从队列中获取 one 对象并“处理”它,那么这就是线程将执行的操作。这就是线程将做的所有。如果您希望线程“等待 [直到] 队列中有一个新数据包......”,那么由您编写等待和处理其他数据包的代码。
猜你喜欢
  • 2021-11-10
  • 2018-06-22
  • 2018-10-02
  • 1970-01-01
  • 2011-03-18
  • 2010-11-14
  • 1970-01-01
  • 2010-11-06
  • 1970-01-01
相关资源
最近更新 更多