2017-07-07 120 views
1

我最近在uni项目上工作,我需要管理一对线程池。 池中的工作线程所做的基本上是对每个相应的队列执行某种类型的弹出操作,如果队列中没有可用的值,最终等待条件变量(pthread_cond_t),并且一旦它们获得一个项目,就解析它并相应地执行操作。 我关心的是,我想没有内存泄漏,并实现我注意到,在主进程退出时在每个线程上调用pthread_cancel肯定是一个坏主意,因为它留下了很多垃圾周围。 关键是,我的第一个想法是使用退出标志,我可以设置线程需要退出时,以便他们可以轻松地释放内存并调用pthread_exit ...我想我应该设置此标志,然后发送向等待条件变量的线程发送广播信号,并在弹出操作后立即检查标志...什么是阻止线程池运行的好方法?

这是否真的是实现良好线程池终止的正确方法?我不觉得这个是多信心...... 我在这里写一些伪代码来解释我谈论

每个池中的线程将运行一些代码的结构是这样的:

/* Worker thread (which will run on each pool thread) */ 
{ /* Thread initialization */ ... } 
loop { 
    value = pop(); 
    { /* Mutex lock because of the shared flag */ ... } 
    if (flag) {{ /* Free memory and unlock mutex */ ... } pthread_exit(); } 
    { /* Unlock the mutex */ ... } 
    { /* Elaborate value */ ... } 
} 
return NULL; 

而且会有某种pool_stopRunning()功能,这将是这样的:提前

/* pool_stopRunning() function code */ 
{ /* Acquire flag mutex */ ... } 
setFlag(flag); 
{ /* Unlock flag mutex */ ... } 
{ /* Acquire queue mutex */ ... } 
pthread_cond_broadcast(...); 
{ /* Unlock queue mutex */ ... } 

谢谢,我只是需要确保有没有看中-ER办法阻止一个线程池。 ..(或者有机会认识更好的方法) 一如既往,对不起,如果有任何错字,我不是和英文扬声器,它现在是一种晚了>:

+2

有必要使用互斥锁来保护国旗。但尽量减少互斥锁的时间。例如,在线程中,复制标志值并释放互斥锁,然后在复制标志值如此说明的情况下退出。不管你做什么,干净的线程终止都需要主线程和其他线程之间的协作,如果涉及到任何共享状态的话。 – Peter

+0

我可能会研究这个https://github.com/Pithikos/C-Thread-Pool/blob/master/thpool.c,查看destroy函数内部,以了解这个lib如何实现它。 – n3wb

+0

首先,你需要这样做吗?如果您只是在进程终止时删除池,那么在Linux/Windows等主流多任务操作系统上,您不需要发出信号/停止/终止任何事情,除非有迫切需要。在停止线程方面,操作系统要比用户代码好得多,(用户代码无法停止在请求停止的线程在另一个内核上运行的线程)。我怀疑过早的停止优化... – ThingyWotsit

回答

0

关于设置标志和减少序列化的对称性,此代码:

{ /* Mutex lock because of the shared flag */ ... } 
if (flag) {{ /* Free memory and unlock mutex */ ... } pthread_exit(); } 
{ /* Unlock the mutex */ ... } 

应该是这样的:

{ /* Mutex lock because of the shared flag */ ... } 
flagcopy = readFlag(); 
{ /* Unlock the mutex */ ... } 
if (flagcopy) {{ /* Free memory ... } pthread_exit(); } 

说了这么多,你可以(应该?)因素的互斥代码到setFlag和readFlag方法。

还有一件事。如果这个标志只是一个布尔值,并且在整个事件关闭之前它只会被改变一次(即它在设置之后永远不会被设置),那么我会争辩说,不需要用互斥锁来保护读取。

我这样说是因为,如果上述假设是真,如果循环的持续时间是非常短,循环迭代频率高,那么你会在业务任务强加不必要的序列化和潜在增加的响应时间不可接受。

+0

这很有趣,但想到它,我有点害怕不检查读取标志前的互斥量,事实是,据我所知,设置任何公共变量不是一个原子操作(或者那里是那个sig_atomic_t类型是?),并且仅仅因为这是一个uni项目,我猜我应该执行它的事情,即使实际上不可能通过这样做来破坏代码,代码将被评估为判断理论上可能存在一些竞争条件的事实 – NokiStrawby

+0

更多地考虑到这一点,最糟糕的情况将是一个工作线程循环一次,而不是一个大问题 – NokiStrawby

0

你所描述的工作,但我会建议不同的方法......

您已经有任务分配给线程,完成所有适当的同步机制。因此,不要用一些新的并行机制来使设计复杂化,只需定义一种称为“停止”的新类型的任务。如果有N线程正在为队列服务并且您想要终止它们,请将N STOP任务推送到队列中。然后等待所有线程终止。(这最后一步可以通过“加入”完成,所以它不应该需要任何新的机制)。

没有琐事,没有大惊小怪。

+1

甚至没有必要发布n'毒药'。当线程识别到自杀请求时,它可以在退出/终止之前将其推回到队列中。这将通过一项任务来完成任意数量的线程:) – ThingyWotsit

+0

感谢您的想法,我没有想到这一点。 事实是,我希望线程终止,只要我发送停止信号,没有完成剩余的任务... 这是一个小问题寿,因为我可以通过弹出ping所有先前的请求队列,然后推动停止任务 – NokiStrawby

+0

..如果排队的项目是指针,则可以使用NULL指针作为毒药,因此在完成工作时不需要删除杀手任务。 – ThingyWotsit

相关问题