简体   繁体   中英

Kill child process when parent process exits in C

I am trying to create a program where it performs some task and exits. however, I want to exit from the program if the user enters some string on the terminal.

The way I thought to solve it: Create a parent process where it is performing the main task. the main task has a loop. create a child process where it is waiting for an input from the user. if the user inputs the exit string, the child process will update a variable and kills itself. The loop in the parent process will check for the value of the variable, if that value is changed by the child process, it will also exit. If the user doesn't input the exit string, the parent process will complete the task and kills itself. at this moment I want to kill the child process also. How can I do that?

Thanks

You could use atexit() to run a cleanup function when the main process exits.

However, processes (assuming you are talking POSIX and classical processes) do not share data with their children, therefore the change of your flag variable will not be visible in the parent.

A much cleaner solution would be to either just use the system provided interaction (namely, the user pressing Ctrl+C, which will cause the tty to send a SIGINT to the session leader (the foreground process), which you can trap to cleanly exit) or check for user input using select()/poll() in the main application.

Thank you for saying what you are actually trying to accomplish here.

You may find it much easier to create a single multithreaded process rather than create two single threaded processes.

  1. Thread #1 does work in a loop and periodically checks a variable exit_flag . If the variable is set, then it calls exit . If it finishes the work, it calls exit .

  2. Thread #2 waits for input from the user. If it gets input, it sets the variable exit_flag .

This way, when you call exit , both threads will automatically exit. You will either need to use a mutex/semaphore or another kind of synchronization, eg, if you have libatomic-ops :

#include "atomic_ops.h"

AO_t exit_flag;

// In thread #2
AO_store(&exit_flag, 1);

// In thread #1
while (!AO_load(&exit_flag)) {
    ...
}

Warning about the above code: Setting a global flag only works this way because the main thread only reads the global flag and nothing else. If you need to send more than one word between threads you'll need some kind of synchronization mechanism, eg, a mutex, semaphore, or AO_store_release paired with AO_store_acquire .

If you use processes instead of threads: Since processes don't share mutable memory by default, it is not as easy as "updating a variable". Each process has its own set of private variables. You would need to set up a region of shared memory or communicate some other way (eg, signal, pipe, socket) which is extra work for you.

Full example

Here is a quick full example. The main thread does "work" that involves counting down from 5. When it reaches 0, it exits and prints a message. The second thread reads user input, when it reads a line starting with 'e' it sets a flag which causes the main thread to exit.

The second thread is created as a detached thread only because we do not need to join with it. It does not affect the correctness of this particular program.

If you call exit , all threads in your program should be terminated, unless there is something wrong with your platform.

Note: This example requires libatomic-ops and assumes you are using POSIX threads.

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <atomic_ops.h>
#include <errno.h>

static AO_t exit_flag;

#define fail(x) fail_func(x, __LINE__)

static void fail_func(int code, int line)
{
    fprintf(stderr, "line %d: failed with code %d\n", line, code);
    abort();
}

static void *input_thread(void *param)
{
    char buf[16], *p;
    (void) param;
    while (1) {
        p = fgets(buf, sizeof(buf), stdin);
        if (!p)
            break;
        if (buf[0] == 'e')
            break;
        else
            puts("unknown command");
    }
    AO_store(&exit_flag, 1);
    return NULL;
}

int main(int argc, char *argv[])
{
    pthread_attr_t attr;
    pthread_t thread2;
    int r, c;
    struct timespec t;
    t.tv_sec = 1;
    t.tv_nsec = 0;
    r = pthread_attr_init(&attr);
    if (r) fail(r);
    // Note: making the thread detached is not actually necessary.
    r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    if (r) fail(r);
    r = pthread_create(&thread2, &attr, input_thread, NULL);
    if (r) fail(r);
    c = 5;
    while (1) {
        if (AO_load(&exit_flag)) {
            puts("thread 1 exiting (canceled)");
            exit(1);
        }
        printf("counter = %d\n", c);
        if (c == 0) {
            puts("thread 1 exiting (finished)");
            exit(0);
        }
        c--;
        r = nanosleep(&t, NULL);
        if (r) fail(errno);
    }
    return 0;
}

Sample output (user input is in ): ):

$ 
counter = 5
counter = 4
counter = 3
counter = 2
counter = 1
counter = 0
thread 1 exiting (finished)
$ 
counter = 5
counter = 4

thread 1 exiting (canceled)

When you fork the child, the parent process will receive the process ID of the child. You can send a SIGTERM signal to the child via the kill() function if you wanted it terminated on-demand. Make sure though to call wait() after sending the SIGTERM signal in order to prevent the child-process from becoming a "zombie" process.

If all you want to do though is get a user-input string back from a child-process, you could simply use popen and cat to start up a child process that will, using cat , echo back whatever the user inputs on the command-line. In order to avoid blocking on the read to the stream created from pipe, you can get the file-descriptor associated with the stream using fileno() , and then use poll or select with a timeout value. When the parent is done, or sees the termiation string input from the user, it then simply calls pclose() and that will terminate the cat process.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM