2013-10-17 49 views
0

这个程序应该是pthreads和信号处理C早期结束

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

当此程序接收第一信号以产生该线程,它输出 “[线程]睡眠1 M [线程]睡眠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); 
} 
+0

OP的问题是,向子进程发送kill SIGUSR1会调用处理程序,然后杀死子进程,以便父进程中的waitpid()返回。问题是OP如何防止waitpid()在SIGUSR1发送给子进程后返回。 –

+0

@charlie谢谢,我不确定到底发生了什么,仍然不知道如何修复它lol – Cyberhawk94

+0

'pthread_create'不是一个从信号处理程序调用的安全函数,所以这看起来像是从一开始就引起麻烦。 – Duck

回答

1

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

儿童

在其睡眠,孩子被阻挡在系统调用(真正的系统调用是nanosleep,用来实现sleep()功能)。当进程在系统调用中接收到信号时,会执行相应的信号处理程序,系统调用将返回错误EINTR,这意味着它已被中断并无法履行其职责。然后您可以决定是否要重新启动系统调用。收到SIGUSR1后,子系统执行的nanosleep系统调用中断,处理程序执行,sleep()立即返回。请注意什么man 3 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. 

正确的方法是,为孩子检查睡眠的返回值(秒数左侧睡),并为再次入睡持续时间。

家长

不像什么查理伯恩斯指出,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)); 

基本上,这个代码是伺候孩子,直到它正常退出或已退出,因为未处理的信号。在你的情况下,父母检查状态变量以确保waitpid返回是一个好主意,因为它期望的事件(一个孩子退出)而不是别的。

+0

这只是一个简短的作业,首次与信号处理混淆。我们的教授明确表示不要担心错误处理,因为这将是我们的下一项任务。但是,你的睡眠检查就像一个魅力,谢谢! – Cyberhawk94

0

放置一个pthread_joinpthread_create后。

+0

是的,除了是在信号处理程序内疯狂。 – Duck

+0

根据我的教授,我们应该能够做到这一点只有创建和取消:/如何加入修复它? – Cyberhawk94

+0

虽然它不一定要放在信号处理功能中,对吧?它可以在main()... –

0

好的,我明白发生了什么事。

当您发送信号时,如果没有通过掩码将其引导至某个特定线程,则进程内的任何线程都可以获取该信号。当SIGUSR1被传递main时,子进程将从sleep中被取消,并且主线程终止杀死处理程序中创建的线程。

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