为啥线程没有在线程池中重用?
Posted
技术标签:
【中文标题】为啥线程没有在线程池中重用?【英文标题】: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();'似乎是个不错的计划。 【参考方案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 对象并“处理”它,那么这就是线程将执行的操作。这就是线程将做的所有。如果您希望线程“等待 [直到] 队列中有一个新数据包......”,那么由您编写等待和处理其他数据包的代码。以上是关于为啥线程没有在线程池中重用?的主要内容,如果未能解决你的问题,请参考以下文章