GNU/Linux >> Belajar Linux >  >> Linux

Waitpid setara dengan batas waktu?

Garpu anak perantara, yang memotong anak asli dan proses batas waktu dan menunggu semua (keduanya) anaknya. Ketika satu keluar, itu akan membunuh yang lain dan keluar.

pid_t intermediate_pid = fork();
if (intermediate_pid == 0) {
    pid_t worker_pid = fork();
    if (worker_pid == 0) {
        do_work();
        _exit(0);
    }

    pid_t timeout_pid = fork();
    if (timeout_pid == 0) {
        sleep(timeout_time);
        _exit(0);
    }

    pid_t exited_pid = wait(NULL);
    if (exited_pid == worker_pid) {
        kill(timeout_pid, SIGKILL);
    } else {
        kill(worker_pid, SIGKILL); // Or something less violent if you prefer
    }
    wait(NULL); // Collect the other process
    _exit(0); // Or some more informative status
}
waitpid(intermediate_pid, 0, 0);

Sangat sederhana :)

Anda bahkan dapat mengabaikan anak perantara jika Anda yakin tidak ada modul lain dalam program yang mengeluarkan proses anak sendiri.


Jangan mencampur alarm() dengan wait() . Anda dapat kehilangan informasi kesalahan dengan cara itu.

Gunakan trik self-pipe. Ini mengubah sinyal apa pun menjadi select() acara yang dapat:

int selfpipe[2];
void selfpipe_sigh(int n)
{
    int save_errno = errno;
    (void)write(selfpipe[1], "",1);
    errno = save_errno;
}
void selfpipe_setup(void)
{
    static struct sigaction act;
    if (pipe(selfpipe) == -1) { abort(); }

    fcntl(selfpipe[0],F_SETFL,fcntl(selfpipe[0],F_GETFL)|O_NONBLOCK);
    fcntl(selfpipe[1],F_SETFL,fcntl(selfpipe[1],F_GETFL)|O_NONBLOCK);
    memset(&act, 0, sizeof(act));
    act.sa_handler = selfpipe_sigh;
    sigaction(SIGCHLD, &act, NULL);
}

Kemudian, fungsi seperti waitpid Anda terlihat seperti ini:

int selfpipe_waitpid(void)
{
    static char dummy[4096];
    fd_set rfds;
    struct timeval tv;
    int died = 0, st;

    tv.tv_sec = 5;
    tv.tv_usec = 0;
    FD_ZERO(&rfds);
    FD_SET(selfpipe[0], &rfds);
    if (select(selfpipe[0]+1, &rfds, NULL, NULL, &tv) > 0) {
       while (read(selfpipe[0],dummy,sizeof(dummy)) > 0);
       while (waitpid(-1, &st, WNOHANG) != -1) died++;
    }
    return died;
}

Anda dapat melihat di selfpipe_waitpid() bagaimana Anda dapat mengontrol batas waktu dan bahkan menggabungkannya dengan select() lainnya berbasis IO.


Ini adalah pertanyaan yang menarik. Saya menemukan sigtimedwait dapat melakukannya.

EDIT 2016/08/29:Terima kasih atas saran Mark Edington. Saya telah menguji contoh Anda di Ubuntu 16.04, berfungsi seperti yang diharapkan.

Catatan:ini hanya berfungsi untuk proses anak. Sayang sekali tampaknya tidak ada cara yang setara dengan WaitForSingleObject Window (unrelated_process_handle, timeout) di Linux/Unix untuk mendapatkan pemberitahuan tentang penghentian proses yang tidak terkait dalam waktu tunggu.

Oke, contoh kode Mark Edington ada di sini:

/* The program creates a child process and waits for it to finish. If a timeout
 * elapses the child is killed. Waiting is done using sigtimedwait(). Race
 * condition is avoided by blocking the SIGCHLD signal before fork().
 */
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

static pid_t fork_child (void)
{
    int p = fork ();

    if (p == -1) {
        perror ("fork");
        exit (1);
    }

    if (p == 0) {
        puts ("child: sleeping...");
        sleep (10);
        puts ("child: exiting");
        exit (0);
    }

    return p;
}

int main (int argc, char *argv[])
{
    sigset_t mask;
    sigset_t orig_mask;
    struct timespec timeout;
    pid_t pid;

    sigemptyset (&mask);
    sigaddset (&mask, SIGCHLD);

    if (sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0) {
        perror ("sigprocmask");
        return 1;
    }

    pid = fork_child ();

    timeout.tv_sec = 5;
    timeout.tv_nsec = 0;

    do {
        if (sigtimedwait(&mask, NULL, &timeout) < 0) {
            if (errno == EINTR) {
                /* Interrupted by a signal other than SIGCHLD. */
                continue;
            }
            else if (errno == EAGAIN) {
                printf ("Timeout, killing child\n");
                kill (pid, SIGKILL);
            }
            else {
                perror ("sigtimedwait");
                return 1;
            }
        }

        break;
    } while (1);

    if (waitpid(pid, NULL, 0) < 0) {
        perror ("waitpid");
        return 1;
    }

    return 0;
}

Linux
  1. UNIX / Linux :Cara menghapus pengguna setara root (Pengguna Non-Root dengan UID 0)

  2. Apa yang poll() lakukan dengan batas waktu 0?

  3. windows setara dengan inet_aton

  1. Pelacakan kernel dengan trace-cmd

  2. Linux:apakah ada pembacaan atau pemulihan dari soket dengan batas waktu?

  3. Apakah ada yang setara dengan cd - untuk cp atau mv?

  1. Menambal Biner Dengan Dd?

  2. Bash:tunggu dengan batas waktu

  3. perintah fallocate() yang setara di OS X?