2012-08-06 81 views
2

我正在寫一個pthreaded網絡應用程序(在C),並認爲我應該創建一個線程來處理每個傳入的連接。然而,我無法理解我應該使用哪種設計,因爲我必須將連接數限制爲固定數量(比如5)。加入任何終止的線程

在閱讀了pthread_join函數的手冊頁,我發現:

There is no pthreads analog of waitpid(-1, &status, 0), that is, "join with any terminated 
thread". If you believe you need this functionality, you probably need to rethink your 
application design. 

這是爲什麼?我怎麼能實現我的目標? 感謝

+0

您是否考慮過在您的套接字上使用非阻塞I/O(可能使用poll,epoll或select)並且只針對所有連接使用單線程?用這種方法肯定可以擴展到5個以上 - 並不難。 – selbie 2012-08-06 02:18:12

回答

0

如果你把一個限制併發線程數,最好的辦法是經常上創建所有線程(工)前面,讓他們在一個無限循環運行,等待工作一個隊列。

然後,主線程負責將工作項目(本例中的連接)添加到該隊列以供工作人員處理。

這個的優點是簡單和速度。簡單,因爲您不必擔心線程開始或停止,除非一次,它們始終運行併爲工作項目提供服務。

速度出於同樣的原因。這就像一個固定大小的線程池。它也以最有效的方式處理工作項目(工作量自動平衡,因爲線程只會在完成前一個項目時纔會要求新項目)。

在僞代碼中,這將如下所示。主線只需將工作項添加到隊列中即可。完成所有工作後,它可以爲每個線程發佈特殊的完成工作項,然後等待它們全部完成。

def queue workqueue = empty 

def main: 
    # start the threads 

    create threadId[5] 
    for each threadId (i): 
     threadId[i] = startThread (worker) 

    # main work loop, finished with (for example) external signal. 

    while not finished: 
     get workitem from some source 
     add workitem to workqueue 

    # Place one special FINISH work item for each thread. 

    for each threadId (i): 
     add FINISH item to workqueue 

    # Wait for all threads to exit, then exit main. 

    for each threadId (i): 
     wait for threadId[i] to exit 

    exit 

工作線程同樣很簡單。無限循環根據需要獲取工作項並處理它們。

如果工作項目是一個結束,退出,保證每個線程有且只有一個整理工作項目:

def worker: 
    # Simple infinite loop to get work items. 

    while true: 
     get workitem from workqueue 

     # Exit if told to. 

     if workitem is a FINISH item: 
      break 

     # Otherwise, process the item and loop around to request next. 

     process workitem 

    exit 
1

這是一個很好的問題。

我認爲推理手冊頁的作者所關注的標準是需要使用waitpid來獲得流程,或者他們將資源懸掛在尾燈上。 pthreads並非如此。如果你不需要知道什麼時候一個特定的線程終止(或者不需要它的返回碼),你可以將它設置爲一個分離的線程;它結束了,就是這樣。相反,如果你真的需要加入一個線索,你應該知道你需要加入哪一個。

進一步思考,父進程與子進程之間存在直接的一對多關係。 Waitpid將等待其子女,操作系統將跟蹤這些孩子並將其交給父母。無論多少代的過程被創建 - 父母收穫其子女,這都會發生。

在一個線程程序中,任何線程都可以創建其他線程。在這種情況下,什麼樣的產品pthread_join意味着什麼?如果所有的線程都被加入到這個catchall線程中,那麼一切都很好。但是如果程序中的某些線程真的需要與其子線程連接,而剩下的線程可以通過該子線程連接起來呢?操作系統或pthreads如何跟蹤每種情況下哪些應用程序不適用於基礎架構?

我想這是可能的,我想每個人都有機會希望在pthreads中有一個通用的waitpid模擬器,但實際上,它可能是一個很大的開銷,實際上,它主要是一個煩惱。當你發現自己處於有多個線程加入但你不知道哪一個會先結束的情況時,你可以建立一個隊列(或者使用一個管道或者其他的東西),然後讓垂死的線程表明它應該被加入。

0

請允許我首先回應paxdiablo的建議,即允許您的線程保持持久性,而不是允許它們終止並重新啓動它們。另外,我回應了selbie建議使用非阻塞I/O,但我會將它與固定線程(我認爲每個CPU只有1個)耦合。使用這兩種方法可以實現更高的工作量並最大限度地提高機器的CPU資源。

但要回答你的問題,如果你想能夠以終止順序與線程連接,你需要線程與收割者的終止順序進行通信。這可以用pipe相對簡單地完成。當線程終止時,它將tid寫入管道,並且收割者讀取tid並執行pthread_join

int tid_pipe[2]; 
pipe(tid_pipe); 

void * thread_proc (void *arg) { 
    /* ... */ 
    /* thread exiting */ 
    pthread_t me = pthread_self(); 
    write(tid_pipe[1], &me, sizeof(me)); 
    return 0; 
} 

/* thread reaper */ 
while (read(tid_pipe[0], &tid, sizeof(tid)) == sizeof(tid)) { 
    pthread_join(tid, &retval); 
    /* ... */ 
} 

但是,作爲替代,你可以讓你的線程運行分離,而不必擔心加盟。相反,您可以使用條件變量讓主線程知道何時可以啓動另一個線程。

void * thread_proc (void *arg) { 
    pthread_detach(pthread_self()); 
    /* ... */ 
    /* thread exiting */ 
    pthread_mutex_lock(&m); 
    if (thread_count++ == 0) pthread_cond_signal(&c); 
    pthread_mutex_unlock(&m); 
    return 0; 
} 

/* thread spawner */ 
while (waiting_for_work()) { 
    pthread_mutex_lock(&m); 
    while (thread_count == 0) pthread_cond_wait(&c, &m); 
    pthread_mutex_unlock(&m); 
    /* ... handle work with new thread ... */ 
} 
0

因爲線程是不是在一個層次結構組織爲是過程,等待「任何」線程將意味着任何線程必須獲得所有線程的全局信息。在某種數據結構(或其他)中組織這樣的信息會有一定的開銷,因爲所有線程的創建和終止都必須經過那裏。這種開銷是自願避免的,線程意味着輕量級和快速。

還有另外一個方面,有些線程甚至無法加入,即那些已經分離或從開始分離的線程。對他們施加這樣的開銷甚至不太可以接受。

-1

如果它是一個多線程的服務器,每個客戶端只有一個線程,那麼只需要對他們進行計數並重新計數。在客戶端線程創建時(即在accept()線程中),在客戶端 - 服務器線程退出之前使用'clientCount'int的原子inc/dec,並且在count> 5時不接受()任何更多連接(即直接從accept()線程發出'太多連接,稍後嘗試'頁面,而不是創建新的服務器客戶端線程)。

試着忘記'加入' - 試想一下,你從來沒有讀過它。