【问题标题】:C: shutdown multithreaded programC:关闭多线程程序
【发布时间】:2017-10-21 19:47:27
【问题描述】:

这个想法是让一个主线程启动多个工作线程。除了发送信号外,没有明确的方法可以退出程序。但是程序也应该在任何地方发生错误时干净地退出。

我试图展示我到目前为止所拥有的东西。标题没有显示,但没有它们应该很清楚。我们有一个 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 与睡眠相比效率更高/更低/同样有效吗?主要的 线程在worker运行时无关,只捕获信号, 我想尽可能避免唤醒。
  • 考虑以下情况:我们捕获 SIGTERM 信号并且处理程序设置 running 变量为假。这会跳过循环(可靠)吗?

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

【问题讨论】:

  • '停止所有线程并优雅地关闭',你应该明白,在一般情况下,这对于普遍可用的语言/操作系统是不可能的,例如。 C 在 Windows/Linux 上。如果可能的话,您应该进行设计,以便在进程终止/重新启动时正确操作不需要“停止所有线程并正常关闭”。
  • 看起来你展示的代码已经满足了大部分要求;有什么特别的方式它不足吗? (如果您希望在特定线程遇到错误时也发生关闭序列,那么最简单的方法就是调用线程,例如 kill(getpid(), SIGINT),以便线程向其包含的进程;然后正常的信号处理序列将照常发生,以便进程以受控方式退出)
  • 我不满意的一点是主循环。如果错误遇到发送一个信号,这个循环应该中断,我可能会使用pause() 而不是sleep()。仅仅调用exit() 是不够的,因为我遇到了我正在使用的库的问题,至少一些清理是绝对必要的。我很高兴有一个干净的解决方案,它可以在 99% 的时间内工作。我展示的代码只是一种设计方法,我希望得到反馈,我可以在哪里改进或者哪里可能存在错误。

标签: c multithreading pthreads


【解决方案1】:

在这种情况下不需要睡眠循环,加入应该就足够了。

在其他用例中,您可以查看 pid 为 -1 的 waitpid,以从任何有话要说的线程获取状态。

如果某些线程先于其他线程停止,信号量在某些情况下可能很有用,要么在线程发布后执行某些操作,要么等到所有线程都已发布。

【讨论】:

  • 谢谢,我试着采纳你的建议。请参阅我的编辑。另外,您能否详细说明在什么情况下需要信号量?当什么线程结束并且线程彼此独立时,我无法做出任何假设。设置全局运行变量应该是一个原子操作,所以我目前看不到任何需要信号量,但我可能会错过一些东西。
  • 信号量可以等待一段时间或直到给定数量的发帖,或者只处理每个发帖并评估是否该关闭。
猜你喜欢
  • 2010-09-21
  • 2010-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-21
  • 1970-01-01
  • 1970-01-01
  • 2010-11-23
相关资源
最近更新 更多