pthreads和信号处理C提前结束

pthreads和信号处理C提前结束,c,linux,pthreads,signals,C,Linux,Pthreads,Signals,这个节目应该是 父级只是无限期地等待任何子级返回(提示,waitpid)。 B孩子设置了两个信号处理程序(提示、信号),然后进入睡眠状态5分钟。 我第一个信号处理程序侦听USR1信号,并在接收到该信号时: 1.创建一个线程(提示,pthread_create)。 A.基本上,线程需要做的就是“打招呼”并睡60分钟 秒。 二,。第二个信号处理程序监听USR2信号,并在接收到该信号后: 1.销毁线程(提示,pthread\u取消) 当该程序收到创建线程的第一个信号时,它将输出 “[线程]睡眠1分钟[

这个节目应该是

父级只是无限期地等待任何子级返回(提示,waitpid)。 B孩子设置了两个信号处理程序(提示、信号),然后进入睡眠状态5分钟。 我第一个信号处理程序侦听USR1信号,并在接收到该信号时: 1.创建一个线程(提示,pthread_create)。 A.基本上,线程需要做的就是“打招呼”并睡60分钟 秒。 二,。第二个信号处理程序监听USR2信号,并在接收到该信号后: 1.销毁线程(提示,pthread\u取消)

当该程序收到创建线程的第一个信号时,它将输出 “[线程]睡眠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);
}
#包括
#包括
#包括
#包括
#包括
#包括
pthread\u t线程;
void*temp()
{
printf(“[thread]hello professor\n”);
printf(“[thread]休眠1分钟\n”);
睡眠(60);
}
无效句柄_USR1(int x)
{
int-s;
printf(“[signal]创建线程\n”);
s=pthread_create(&thread,NULL,&temp,NULL);
}
无效句柄_USR2(int x)
{
int-s;
printf(“[signal]正在销毁线程\n”);
s=pthread_cancel(线程);
}
内部主(空)
{
int status=0;
如果(fork()!=0)
{
printf(“[parent]正在等待…”\n”);
waitpid(-1,状态为0(&S);
}
其他的
{
printf(“[child]创建线程:kill-USR1%d\n”,getpid());
printf(“[child]结束线程:kill-USR2%d\n”,getpid());
printf(“[child]设置信号处理程序\n”);
信号(SIGUSR1,手柄\ USR1);
信号(SIGUSR2,手柄\ USR2);
printf(“[child]等待信号\n”);
睡眠(300);
}
返回(0);
}

pthread\u创建后放置一个
pthread\u join
正如Charlie Burns指出的那样,两个进程最终都会由于信号退出,但原因不同

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

正确的方法是让孩子检查睡眠的返回值(剩下的睡眠秒数),然后在此期间再次睡眠

父母亲 与Charlie Burns指出的不同,父对象中的waitpid()不会返回,因为子对象接收到信号。由于子进程退出,它将返回。如果子进程没有处理该信号,因此被它终止(未处理的信号导致进程终止),它将返回,因为子进程的原因。您可以(也应该)按照
man 2 waitpid
中的说明,使用WIFEXITED宏及其伴随项检查。本手册页底部的示例非常好:

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));

基本上,此代码所做的是等待子级,直到它正常退出或由于未处理的信号而退出。在您的情况下,最好让父级检查status变量,以确保waitpid返回的原因是它预期的事件(子级退出),而不是其他事件。

好的,我知道发生了什么

当您发送一个信号时,没有通过掩蔽将其定向到特定线程,进程中的任何线程都可以获得它。当SIGUSR1在
main
中被传递时,子线程从
sleep
中被吹出,并且主线程终止终止终止在处理程序中创建的线程


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

OP的问题是,向子进程发送kill SIGUSR1会调用处理程序,然后杀死子进程,因此waitpid()在父项返回中。问题是OP如何阻止waitpid()在SIGUSR1发送给孩子后返回。@查理,谢谢,我不确定到底发生了什么,仍然不知道如何修复它lol
pthread_create
从信号处理程序调用不是一个安全的函数,所以这看起来从一开始就是在招惹麻烦。@duck我们的教授就是这么说的,他的工作很好:/Yeah的可能复制品,只是信号处理程序内部有点疯狂。根据我的教授,我们应该只使用create和cancel就能做到这一点:/join如何修复它?它不一定要放在信号处理函数中,对吗?它可能在main()中……那又怎样,在sleep300之后添加它?这只是一个简短的任务,第一次干扰信号处理。我们的教授明确表示不要担心错误处理,因为这将是我们的下一个任务。不过,你的睡眠检查很有魅力,谢谢!
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));