Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
612 views
in Technique[技术] by (71.8m points)

linux - pthreads and signal handling C ending early

This program is supposed to

The parent simply waits indefinitely for any child to return (hint, waitpid). b. The child sets up two signal handlers (hint, signal) and goes to sleep for 5 minutes. i. The first signal handler listens for the USR1 signal, and upon receiving it: 1. Creates a thread (hint, pthread_create). a. Basically, all that the thread needs to do is “say hello” and sleep for 60 seconds. ii. The second signal handler listens for the USR2 signal, and upon receiving it: 1. Destroys the thread (hint, pthread_cancel).

When this program receives the first signal to create the thread, it outputs "[thread] sleeping for 1 m[thread] sleeping for 1 minute" and then ends, it never waits for the 2nd signal, what am i doing wrong?

#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
");
    printf("[thread] sleeping for 1 minute
");
    sleep(60);
}
void handle_USR1(int x)
{
    int s;
    printf("[signal] creating the thread
");
    s = pthread_create(&thread, NULL, &temp, NULL);
}

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

int main(void)
{
    int status = 0;

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

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

     printf("[child] waiting for signals
");
     sleep(300);
    }
    return (0);
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As Charlie Burns pointed out, both processes eventually exit as a consequence of the signal, but for different reasons.

Child

During its sleep, the child is blocked in a system call (the actual system call is nanosleep, used to implement the sleep() function). When a process receives a signal while in a system call, the corresponding signal handler is executed and the system call returns an error, EINTR, which means it has been interrupted and couldn't fulfill its duty. You can then decide if you want to restart the system call or not. Upon receiving SIGUSR1, the nanosleep system call executed by the child is interrupted, the handler is executed and sleep() returns immediately. Notice what man 3 sleep says about the return value of 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.

The correct way would be for the child to check for the return value of sleep (number of seconds left to sleep), and sleep again for that duration.

Parent

Unlike what Charlie Burns pointed out, waitpid() in the parent does not return because of the child receiving a signal. It returns because of the child exiting. It would return because of the child IF the child did not handle the signal, and thus was killed by it (an unhandled signal causes the process to die). You can (and should) check that using the WIFEXITED macro and its companions as described in man 2 waitpid. The example at the bottom of this man page is very good:

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

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

Basically, what this code does is wait on the child until it has exited normally or has exited because of an unhandled signal. In your case, it would be a good idea for the parent to check the status variable to make sure that waitpid returned because of the event it expects (a child exiting) and not something else.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...