2017-10-21 166 views
1

的想法是有其啓動多個工作線程一個主線程。除了發送信號之外,沒有明確的方式退出程序。但是程序也應該在任何地方發生錯誤時乾淨地退出。C:關機的多線程程序

我試圖表明我有什麼至今。標題沒有顯示,但沒有它們應該清楚。我們有一個主函數main.c,其中main函數開始於worker.c,它具有線程管理和object.c的抽象,一個工作線程的特定實現。將會有多種不同的實現,但都具有相同的結構(即,具有while(running)循環的process()函數)。

的main.c

#include <signal.h> 

#define NUM_THREADS 5 

volatile static sig_atomic_t running = 1; 
volatile static int exit_code = 0; 

void shutdown(int s) 
{ 
    running = 0; 
    exit_code = s; 
} 

int main(int argc, char **argv) 
{ 
    struct sigaction sa; 
    sa.sa_handler = shutdown; 
    sigaction(SIGINT, &sa, 0); 

    thread_obj *threads[NUM_THREADS]; 
    for (int i = 0; i < NUM_THREADS; ++i) { 
     threads[i] = worker_new(); 
    } 


    for(int i = 0; i < NUM_THREADS; ++i) { 
     pthread_join(threads[i]->worker, NULL); 
     theads[i]->free(); 
     free(threads[i]); 
    } 

    return exit_code; 
} 

worker.c

#include <pthread.h> 

struct thread_object { 
    pthread_t worker; 
    int *running: 
    void *obj; 
    void (*process)(void *obj, int *running); 
    void (*free)(void *obj); 
}: 

void *thread_func(void *obj) 
{ 
    struct thread_object *tmp = obj; 
    tmp->process(tmp->obj, tmp->running): 
    return; 
} 

struct thread_object *worker_new(void *obj) 
{ 
    struct thread_object *tmp = malloc(sizeof(*tmp)); 
    tmp->obj = obj; 
    tmp->running = running; 
    tmp->process = obj->process; 
    tmp->free = obj->free; 
    pthread_create(&(tmp->worker), NULL, thread_func, obj); 
    return tmp; 
} 

object.c

#include "main.h" 

void process(void *obj, int *running) 
{ 
    struct special_object *tmp = obj; 
    while(*running) { 
     // do something 
     if(error) { 
      kill(getpid(), SIGTERM); 
      break; 
     } 
    } 
    // cleanup tasks 
} 

現在的問題是,這將是最乾淨,最快捷,最簡便的方式在C中實現這一點?兩個要點:停止所有線程並正常關閉,如果a)收到SIGINT等信號或者b)至少有一名員工遇到錯誤。

編輯:我想包括的建議,但現在也有一些後續問題:

  • 在pthread_join更多/更少/同等有效的睡眠?主要 線程無關而工人來看,只有趕上信號, 和我想避免儘可能多的喚醒越好。
  • 考慮以下幾點:我們趕上SIGTERM信號處理程序的 running變量設置爲false。這會跳過循環(可靠)嗎?

kill(getpid(), SIGTERM); while (*running) {;}

+0

「停止所有線程和正常關機」好,你應該明白,這是,在一般情況下,通常可用的語言/ OS,如不可能的。 C在Windows/Linux上。如果完全可能,您應該設計以便在進程終止/重新啓動時正確運行'停止所有線程並正常關閉'。 –

+0

它看起來像你已經顯示的代碼已經符合大部分要求;有沒有一些特別的方法可以縮短? (如果你想讓關閉序列在特定線程遇到錯誤時也發生,最簡單的方法就是讓線程調用例如kill(getpid(),SIGINT),以便線程發送一個信號給它的包含進程;然後正常的信號處理序列將照常進行,以便以受控方式退出進程) –

+0

我不滿意的一件事是主循環。我可能可以使用'pause()'而不是'sleep()',如果遇到錯誤發送一個信號,這個循環會中斷。 僅僅調用'exit()'是不夠的,因爲我遇到了使用庫的問題,至少有一些清理是絕對必要的。我很滿意一個乾淨的解決方案,可以在99%的時間內工作。我所展示的代碼只是一種設計方法,我希望得到反饋,在那裏我可以改進或者可能出現錯誤。 – flowit

回答

0

在這種情況下,睡眠循環是不需要的,連接應該夠了。

在其他使用情況你可以看看waitpid函數爲-1的PID從該有話要說任何線程獲取狀態。

如果某些線程在其他線程之前停止,在某些情況下可能會有用,或者在線程發佈後執行某些操作,或者等到所有線程都發布後再執行某些操作。

+0

謝謝,我試圖包含你的建議。看我的編輯。另外,您能否詳細說明在什麼情況下需要信號量?什麼線程結束,線程是相互獨立的,我不能做任何假設。設置全局運行變量應該是一個原子操作,所以我目前看不到有任何信號需要,但我可能會錯過一些東西。 – flowit

+0

信號量可以等待一段時間,或者等到給定數量的信息發送給它,或者只是處理每個信息並評估是否要關閉它。 – Surt