2017-07-07 53 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

相關問題