• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

[gelöst] fork, kill es soll nicht alles beendet werden

Mr. S

Member
Hallo!

Ich habe ein großes Problem! Ich habe ein Programm das ungefähr 3 Stunden lang laufen soll. Zwischendurch ruft das Programm Unterprogramme und PHP-Scripte auf. Diese sollen nach einiger Zeit, wenn sie nicht schon fertig sind, vom Programm beendet werden. Dafür habe ich mir ein kleines Programm (execw) geschrieben, das die Zeiten überwacht und ggf. die Programme/Scripte beendet. Das funktioniert auch ganz gut, nur leider wird da auch das Hauptprogramm beendet und das darf nicht passieren! Ich habe mir mal ein Testprogramm geschrieben und ein Testscript erstellt um rauszufinden wo das Problem liegt. Leider finde ich den Fehler nicht, wahrscheinlich ist es ganz einfach. Hier der Code:

execw.cpp
Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc,char** argv)
{
	if(argc < 3) {
		printf("Nicht genügend Argumente!\n   (%d Argumente)\n",argc);
		return 4;
	}
	pid_t pid;
	int status;
	pid = fork();
	//argv[0] Eigener Programmpfad
	//argv[1] Ausführen
	//argv[2] Zeit
	//argv[3] Argumente
	if (pid < 0) {
		printf("Fehler : fork () lieferte %u.\n", pid);
		exit(1);
	} else if (pid == 0) {
		printf("Kind : PID = %u. PID des Eltern = %u\n", getpid(), getppid());
		execv(argv[1], &argv[3]);
		exit(3);
	} else {
		printf("Eltern: PID = %u. PID des Kindes = %u\n", getpid(), pid);
		int timer = atoi(argv[2]);
		while((pid = waitpid(-1, &status, WNOHANG)) == 0) {
			sleep(1);
			if(timer < 0) {
				char buffer[1024];
				memset(buffer,0,1024);
				sprintf(buffer,"probleme -- timer_done=%d timer_set=%s",timer * -1,argv[2]);
				for(int i=3;i<argc;i++) {
					strcat(buffer," ");
					strcat(buffer,argv[i]);
				}
				puts(buffer);
				//system(buffer);
				kill(pid,SIGKILL);
			}
			timer--;
		}
		printf("Eltern: Kind mit PID %u ", pid);
		if(WIFEXITED(status) != 0) {
			printf("wurde mit Status %d beendet\n", WEXITSTATUS(status));
			return status;
		} else {
			printf("wurde anormal beendet.\n");
			return 2;
		}
	}
	return 0;
}

test.cpp
Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>

#define BUFFERLAENGE 512

int irand( int a, int e)
{
	srand((unsigned)time(NULL));
    double r = e - a + 1;
    return a + (int)(r * rand()/(RAND_MAX+1.0));
}

int main(int argc,char** argv)
{
	char buffer[BUFFERLAENGE];
	int i = irand(5,20);
	memset(buffer,0,BUFFERLAENGE);
	for(i=0;i<300;i++) {
		printf("Start: ");
		sprintf(buffer,"./execw /usr/bin/php 10 -f /var/www/virtual/phpscript.php -- TIME=%d",irand(5,20));
		printf("%s\n",buffer);
		system(buffer);
		printf("Ende\n\n");
		sleep(4);
	}
}

phpscript.php
Code:
<?php
foreach($argv as $i => $arg) {
	if(strstr($arg,"=") != false) {
		$x = split("=",$arg);
		$_REQUEST[$x[0]] = $x[1];
	}
}
print "PHP-Testscript\n\nUmgebung:".print_r($_REQUEST,true);
flush();
sleep($_REQUEST["TIME"]);
print "PHP-Ende\n";
?>

testit.sh
Code:
#!/bin/sh

rm test
rm execw

g++ execw.cpp -o execw
g++ test.cpp -o test

./test
Das Testprogramm startet über execw das PHP-Script und übergibt eine Zufallszahl. Diese Zahl wartet PHP ab. Der Parameter 10 weisst execw an das Programm nach 10 Sekunden zu beenden, falls es noch nicht fertig ist. Leider wird hierbei auch immer das Programm test beendet, was nicht passieren soll!
Solange das Script sich vor der Zeit beendet gibt es keine Probleme. Nur wenn das Script beendet wird, werden gleich alle 3 Programme (PHP, test und execw) beendet und das soll eigentlich nicht passieren. execw wurde geschrieben um fork und kill aus dem Hauptprogramm raus zu halten weil dieses begrenzte Ausführen von Programmen später auch noch andere Programmen ermöglicht werden soll. Wahrscheinlich muss ich das in einem neuen Thread starten, oder? Wie macht man das unter Linux? Ich kenn das nur von Windows.

Vielen Dank!
 
Code:
		execv(argv[1], &argv[3]);
Ich glaube du suchst eher execvp().
Code:
		int timer = atoi(argv[2]);
Und strtol() hier.
Code:
		while((pid = waitpid(-1, &status, WNOHANG)) == 0) {
Dir fehlt ein SIGCHLD-Handler.
Code:
				sprintf(buffer,"probleme -- timer_done=%d timer_set=%s",timer * -1,argv[2]);
timer * -1 == -timer
Code:
				kill(pid,SIGKILL);
Das macht keinen Sinn, der Prozess ist doch schon im Zombie-Status.
Code:
g++ execw.cpp -o execw
g++ test.cpp -o test
Hier reicht ein C-Compiler.
 
OP
M

Mr. S

Member
jengelh schrieb:
Code:
		while((pid = waitpid(-1, &status, WNOHANG)) == 0) {
Dir fehlt ein SIGCHLD-Handler.
Was meinst du?

jengelh schrieb:
Code:
				kill(pid,SIGKILL);
Das macht keinen Sinn, der Prozess ist doch schon im Zombie-Status.
Ja, vielen Dank, das war's!
Code:
                printf("Eltern: PID = %u. PID des Kindes = %u\n", getpid(), pid); 
                pid_t upid; 
                upid = pid; 
                int timer = atoi(argv[2]); 
                while((pid = waitpid(-1, &status, WNOHANG)) == 0) { 
                        sleep(1); 
                        if(timer < 0) { 
                                char buffer[1024]; 
                                memset(buffer,0,1024); 
                                sprintf(buffer,"probleme -- timer_done=%d timer_set=%s",timer * 
-1,argv[2]); 
                                for(int i=3;i<argc;i++) { 
                                        strcat(buffer," "); 
                                        strcat(buffer,argv[i]); 
                                } 
                                puts(buffer); 
                                //system(buffer); 
                                kill(upid,SIGKILL); 
                        } 
                        timer--; 
                }
In der Schleife war pid ja immer 0 daher wurde alles beendet, jetzt funktionierts. Ich verwende g++ weil das original-programm c++ benutzt und auch wesentlich umfangreicher ist. Dies war nur ein kleiner Test um den Fehler zu finden.

Vielen Dank
 
Oben