Здравствуйте!
Задача:
следить за дочерним процессом и перезапускать его в случае завершения.
Я принял следующий подход к этой задаче:
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#define NUM_THREADS 3
struct Arg {
pid_t pid;
};
void* product(void* arg) {
while (1) {
// do smth complex
sleep(1);
printf("process %d\n", getpid());
}
}
void* control(void* arg) {
int status;
pid_t w;
do {
w = waitpid((((Arg*)arg)->pid), &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));
exit(EXIT_SUCCESS);
}
void startProcess() {
pid_t cpid;//, w;
pthread_t thread;
//int status;
cpid = fork();
if (cpid == -1) {
perror("fork");
printf("WE SHOULD RESTART PROCESS\n");
exit(EXIT_FAILURE);
}
if (cpid == 0) { // Code executed by child
printf("Child PID is %ld\n", (long) getpid());
Arg arg;
arg.pid = cpid;
pthread_create(&thread,0, &product, &arg);
}
else { // Code executed by parent
Arg arg;
arg.pid = cpid;
pthread_create(&thread,0, &control, &arg);
return;
}
}
int main() {
for(int i=0; i<NUM_THREADS; ++i) {
startProcess();
}
return 0;
}
Насколько я понял, данный подход не совсем правильный.
Возможно, вы можете указать на мои ошибки и подсказать правильный путь.
Спасибо
Алексей
03.10.13 15:49: Перенесено модератором из 'C/C++' — Кодт
Здравствуйте, Handler, Вы писали:
H>Здравствуйте!
H>Задача:
H>следить за дочерним процессом и перезапускать его в случае завершения.
Дарю:
#/bin/bash
while /bin/true; do
process
done
H>Я принял следующий подход к этой задаче:
H>#define NUM_THREADS 3
Использовать вперемешку треды и форки — значит нарываться на грабли.
void startProcess() {
pid_t cpid;//, w;
pthread_t thread;
//int status;
cpid = fork();
if (cpid == -1) {
perror("fork");
printf("WE SHOULD RESTART PROCESS\n");
exit(EXIT_FAILURE);
}
if (cpid == 0) { // Code executed by child
printf("Child PID is %ld\n", (long) getpid());
Arg arg;
arg.pid = cpid;
pthread_create(&thread,0, &product, &arg);
}
else { // Code executed by parent
Arg arg;
arg.pid = cpid;
pthread_create(&thread,0, &control, &arg);
return;
}
}
Зачем здесь треды и какая польза ожидается от их применения?
int main() {
for(int i=0; i<NUM_THREADS; ++i) {
startProcess();
}
return 0;
}
Программа запустит несколько тредов (если успеет — тред не обязан стартовать сразу же), после чего тут же преспокойно завершится (треды, которые успели запуститься, благополучно сдохнут на первом же cancellation point).
Как минимум , было бы неплохо подождать завершения работы треда (pthread_join()).
H>Насколько я понял, данный подход не совсем правильный.
H>Возможно, вы можете указать на мои ошибки и подсказать правильный путь.
Ошибки:
— Для этой задачи не нужны треды
— Для этой задачи не нужен С, достаточно простенького скрипта на шелле.
— Но даже если вдруг очень-очень надо написать такой враппер на С, запускать процесс в юниксах принято через идиому fork+exec, а не через треды-бреды. Т.е. форкаемся, проверяем pid, и если мы в потомке — замещаем текущий процесс нужной программой через exec*().
Правильный путь:
— Не изобретать велосипед, а использовать имеющуюся в вашем дистрибутиве линукса/юникса обвязку для запуска демонов ака сервисов (сейчас пошла мода называть демонов "сервисами" — линукс становится дружелюбнее к религиозно одаренным).
— Если очень надо именно свой лисапет (стандартная обвязка не подходит), то все равно правильнее такие вещи делать на шелле, а не компилябельным бинарем.