pthreads和信号处理C提前结束

时间:2013-10-17 02:31:19

标签: c linux pthreads signals

这个程序应该

父母只是无限期地等待任何孩子返回(提示,waitpid)。 湾孩子设置了两个信号处理程序(提示,信号)并进入睡眠状态5分钟。 一世。第一个信号处理程序侦听USR1信号,并在收到它时: 1.创建一个线程(提示,pthread_create)。 一个。基本上,线程需要做的就是“打个招呼”并睡60个小时 秒。 II。第二个信号处理程序侦听USR2信号,并在收到它时: 1.销毁线程(提示,pthread_cancel)。

当该程序收到第一个创建线程的信号时,它输出  “[线程]睡了1米[线程]睡了1分钟” 然后结束,它永远不会等待第二个信号,我做错了什么?

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>

pthread_t thread;

void* temp()
{
    printf("[thread] hello professor\n");
    printf("[thread] sleeping for 1 minute\n");
    sleep(60);
}
void handle_USR1(int x)
{
    int s;
    printf("[signal] creating the thread\n");
    s = pthread_create(&thread, NULL, &temp, NULL);
}

void handle_USR2(int x)
{
    int s;
    printf("[signal] destroying the thread\n");
    s = pthread_cancel(thread);
}

int main(void)
{
    int status = 0;

    if(fork() != 0)
    {
     printf("[parent] waiting.....\n");
     waitpid(-1, &status, 0);
    }
    else
    {
     printf("[child] to create the thread: kill -USR1 %d\n", getpid());
     printf("[child] to end the thread: kill -USR2 %d\n", getpid());
     printf("[child] setting up signal handlers\n");

     signal(SIGUSR1, handle_USR1);
     signal(SIGUSR2, handle_USR2);

     printf("[child] waiting for signals\n");
     sleep(300);
    }
    return (0);
}

3 个答案:

答案 0 :(得分:1)

正如查理·伯恩斯所指出的那样,这两个过程最终都会因信号而退出,但出于不同的原因。

在睡眠期间,子系统在系统调用中被阻止(实际系统调用为nanosleep,用于实现sleep()功能。当进程在系统调用中收到信号时,将执行相应的信号处理程序,系统调用将返回错误EINTR,这意味着它已被中断且无法履行其职责。然后,您可以决定是否要重新启动系统调用。收到SIGUSR1后,子进程执行的nanosleep系统调用被中断,执行处理程序并且sleep()立即返回。请注意man 3 sleep关于sleep()的返回值的说明:

Zero if the requested time has elapsed, or the number of seconds left to sleep, if the call was interrupted by a signal handler.

正确的方法是让孩子检查睡眠的返回值(剩余睡眠的秒数),并在该持续时间内再次睡眠。

与Charlie Burns指出的不同,父母中的waitpid()因为孩子收到信号而没有返回。它会因孩子退出而返回。如果孩子没有处理信号,它就会返回,因此被它杀死(未处理的信号导致该过程死亡)。您可以(并且应该)使用WIFEXITED宏及其随附伙伴检查man 2 waitpid中所述。本手册页底部的示例非常好:

do {
   w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
   if (w == -1) {
       perror("waitpid");
       exit(EXIT_FAILURE);
   }

   if (WIFEXITED(status)) {
       printf("exited, status=%d\n", WEXITSTATUS(status));
   } else if (WIFSIGNALED(status)) {
       printf("killed by signal %d\n", WTERMSIG(status));
   } else if (WIFSTOPPED(status)) {
       printf("stopped by signal %d\n", WSTOPSIG(status));
   } else if (WIFCONTINUED(status)) {
       printf("continued\n");
   }
} while (!WIFEXITED(status) && !WIFSIGNALED(status));

基本上,这段代码的作用是等待孩子正常退出或由于未处理的信号而退出。在你的情况下,父母检查状态变量是一个好主意,以确保waitpid因为它所期望的事件(一个孩子退出)而退回,而不是其他东西。

答案 1 :(得分:0)

pthread_join之后放置pthread_create

答案 2 :(得分:0)

好的,我知道发生了什么。

当您发送信号时,无需通过屏蔽将其指向特定线程,进程中的任何线程都可以获取它。当SIGUSR1被传递时,main被传递出sleep并且主线程终止,从而终止了在处理程序中创建的线程。

这里有很多问题涉及如何将信号引导到单个线程和/或使用sigaction重新启动系统调用,如果这也是您想要解决它的方向。