的想法是有其啓動多個工作線程一個主線程。除了發送信號之外,沒有明確的方式退出程序。但是程序也應該在任何地方發生錯誤時乾淨地退出。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) {;}
「停止所有線程和正常關機」好,你應該明白,這是,在一般情況下,通常可用的語言/ OS,如不可能的。 C在Windows/Linux上。如果完全可能,您應該設計以便在進程終止/重新啓動時正確運行'停止所有線程並正常關閉'。 –
它看起來像你已經顯示的代碼已經符合大部分要求;有沒有一些特別的方法可以縮短? (如果你想讓關閉序列在特定線程遇到錯誤時也發生,最簡單的方法就是讓線程調用例如kill(getpid(),SIGINT),以便線程發送一個信號給它的包含進程;然後正常的信號處理序列將照常進行,以便以受控方式退出進程) –
我不滿意的一件事是主循環。我可能可以使用'pause()'而不是'sleep()',如果遇到錯誤發送一個信號,這個循環會中斷。 僅僅調用'exit()'是不夠的,因爲我遇到了使用庫的問題,至少有一些清理是絕對必要的。我很滿意一個乾淨的解決方案,可以在99%的時間內工作。我所展示的代碼只是一種設計方法,我希望得到反饋,在那裏我可以改進或者可能出現錯誤。 – flowit