"Christmas - the time to fix the computers of your loved ones" « Lord Wyrm

C - Kindprozess terminiert ab und zu nicht

muene 17.01.2009 - 23:48 1424 6
Posts

muene

Addicted
Avatar
Registered: Jan 2004
Location: @Home
Posts: 430
Hi,

hab als Uni Hü ein C-Programm zu schreiben welches 2 Kindprozesse erzeugt.
Beim aufrufen des Programms gibt man als Argument ein Wort/Satz/... an. Der Vaterprozess verändert dann zufällig eines der Zeichen und sendet den neuen String dann mittels pipe an das erste Kind. Das erste Kind verändert wieder ein zufälliges Zeichen und sendet es ebenfalls über eine pipe an das 2e Kind. dieses verändert wieder ein Zeichen und gibt es dann anschließend aus. (mittels der Option -v wird jeder schritt angezeigt).
Das Programm selbst hab ich schon und funktioniert auch. Nur bei ca. jedem 2en mal wirft mir das Programm den Fehler aus, dass der 2e Kindprozess nicht richtig terminiert. Hab jetzt schon eine weile gegrübelt wieso das so ist, aber ich komm leider auf kein Ergebnis. Weiß jemand wieso das so ist, bzw. was ich korrigieren muss?

Ich poste hier mal den Code:

Edit: Sourcecodefile + Makefile im 3en Post

Vielen Dank im vorhinein.
lg

Edit: wie stell ichs ein, dass der Code in mehr als einer Zeile angezeigt wird?
Bearbeitet von muene am 18.01.2009, 00:41

COLOSSUS

Administrator
Frickler
Avatar
Registered: Dec 2000
Location: ~
Posts: 11900
Da macht wohl grade jemand SysProg... :D

Paste den Sourcecode halt extern. Pastebins gibt es ja genug. Oder noch besser: Tarball mit Makefile und Co. zum Download anbieten.

muene

Addicted
Avatar
Registered: Jan 2004
Location: @Home
Posts: 430
Jawohl Sysprog :)
Zip-File mit SourceCode und Makefile

Edit: Angabe was das Programm machen soll
Bearbeitet von muene am 18.01.2009, 00:43

t3mp

I Love Gasoline
Avatar
Registered: Mar 2003
Location: upstairs
Posts: 6254
Da bleibt der Code aber nicht dauerhaft erhalten...

Hmm was erwartet sich denn oc.at für einen Zeilenumbruch? Ich vermute einmal die DOS-Konvention.

DirtyHarry

aka robobimbo
Avatar
Registered: Apr 2001
Location: outer space
Posts: 464
Wenn ein Prozess nicht terminiert, ist das meist ein Zeichen dass nicht alle Filedeskriptoren geschlossen sind.

Ich hab mich ein wenig rumgespielt, hab allerdings ein paar Variablennamen geändert damit es ein wenig sprechender wird.

Code:
/*
 *
 *
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>

#define MAXCHAR 80
#define STDIN  0
#define STDOUT 1
#define STDERR 2

const char *szCommand = "<not yet set>";
static int pPipe_m2c[2];
static int pPipe_c2c[2];
int aus=0;

static pid_t pid_c1;
static pid_t pid_c2;

static FILE *pStream_c1 = (FILE *) 0;
static FILE *pStream_c2 = (FILE *) 0;

void AllocateResources(void);
void Bailout(const char *szMessage);
void ChildProcess_c1(void);
void ChildProcess_c2(void);
void FatherProcess(char *eingabe);
void FreeResources_c1(void);
void FreeResources_c2(void);
void Usage(void);

int main(int argc, char **argv) {
	int c;
	char eingabe[MAXCHAR];
	pid_t wpid;
	pid_t wpid1;
	int status;
	extern char *optarg;

	szCommand = argv[0];

	while ( (c=getopt(argc, argv, "v:")) !=EOF){
		switch(c){
			case 'v':	aus=1;
				strcpy(eingabe, optarg);
			break;
			default:
			break;
		}
	}

	if(aus==0)
	{
		if(argc!=2)
		{
			Usage();
		}
		strcpy(eingabe, argv[1]);
	}


	if (argc>3)
	{
		Usage();
	}
	AllocateResources();

	switch (pid_c1 = fork()) {
	case -1:
		Bailout("Fork failed!");
		break;
	case 0:
		ChildProcess_c1();
		break;
	default:
		switch (pid_c2 = fork()) {
			case -1:
				Bailout("Fork failed!");
				break;
			case 0:
				ChildProcess_c2();
				break;
			default:
				FatherProcess(eingabe);

				while((wpid = wait(&status)) !=pid_c1) {
					if(wpid != -1) {
						continue;
					}
					if (errno == EINTR)	{
						continue;
					}

					Bailout("Error waiting for child process!");
				}

				while((wpid1 = wait(&status)) !=pid_c2) {
					if(wpid1 != -1)
					{
						continue;
					}
					if (errno == EINTR)
					{
						continue;
					}

					Bailout("Error waiting for child process!2");
				}
				break;
		}
		break;
	}
	exit(EXIT_SUCCESS);
}

void Bailout(const char *szMessage)
{
	if (szMessage != (const char *) 0)
	{
		 printf("%s",szMessage);

	}

	FreeResources_c1();
	/* FreeRessources Aufruf vom zweiten Child hat hier gefehlt */
	FreeResources_c2();

	exit(EXIT_FAILURE);

}

void FreeResources_c1(void)
{
	if (pStream_c1 != (FILE *) 0)
	{
		if (fclose((FILE *) pStream_c1) == EOF)
		{
			pStream_c1 = (FILE *) 0;
			Bailout("Cannot close pipe stream!");
		}
		pStream_c1 = (FILE *) 0;

	}
}

void FreeResources_c2(void)
{
	if (pStream_c2 != (FILE *) 0)
	{
		if (fclose((FILE *) pStream_c2) == EOF)
		{
			pStream_c2 = (FILE *) 0;
			Bailout("Cannot close pipe stream!");
		}
		pStream_c2 = (FILE *) 0;

	}
}

void AllocateResources(void)
{
	if (pipe(pPipe_m2c) == -1)
	{
		Bailout("Cannot create pipe!");
	}
	if (pipe(pPipe_c2c) == -1)
	{
		Bailout("Cannot create pipe!");
	}

}

void Usage(void)
{
	(void) fprintf(stderr,"USAGE: %s [Text] [-v] [Text]\n",szCommand);

	Bailout((const char *) 0);
}

void FatherProcess(char *eingabe)
{
	int a,b,c;

	if (close(pPipe_m2c[STDIN]) == -1)
	{
		Bailout("Error closing the read descriptor!");
	}

	if ((pStream_c1 = fdopen(pPipe_m2c[STDOUT], "w")) == (FILE *) NULL)
	{
		Bailout("Cannot open pipe for writing!");
	}
	if(aus==1)
	{
		printf("Mutter: erhalten: %s\n", eingabe);
	}

	srand(time(NULL)+7);
	a=rand()%(strlen(eingabe));
	srand(time(NULL)+8);
	c=rand()%2;
	srand(time(NULL)+9);
	if(c<1)
	{
		b=(rand()%26)+65;
	}
	if(c==1)
	{
		b=(rand()%26)+97;
	}
	eingabe[a]=b;
	if(aus==1)
	{
		printf("Mutter: weiter  : %s\n", eingabe);
	}

	if(fprintf(pStream_c1,"%s\n", eingabe) < 0)
	{
		Bailout("Cant write to pipe!");
	}

	FreeResources_c1();
	// Vaterprozess braucht die Daten von Child2 nicht
	FreeResources_c2();
}

void ChildProcess_c1(void)
{
	int a,b,c;
	char buffer[MAXCHAR +1];
	
	if (close(pPipe_m2c[STDOUT]) == -1)
	{
		Bailout("Error closing the write descriptor!");
	}
	if ((pStream_c1 = fdopen(pPipe_m2c[STDIN], "r")) == (FILE *) NULL)
	{
		Bailout("Cannot open pipe for reading!");
	}

	fgets(buffer, MAXCHAR, pStream_c1);

	if(aus==1)
	{
		printf("Kind1 : erhalten: %s", buffer);
	}

	srand(time(NULL));
	a=rand()%(strlen(buffer)-1);
	srand(time(NULL)+1);
	c=rand()%2;
	srand(time(NULL)+2);
	if(c<1)
	{
		b=(rand()%26)+65;
	}
	if(c==1)
	{
		b=(rand()%26)+97;
	}
	buffer[a]=b;

	if(aus==1)
	{
		printf("Kind1 : weiter  : %s", buffer);
	}
	
	if (close(pPipe_c2c[STDIN]) == -1)
	{
		Bailout("Error closing the read descriptor!");
	}

	if ((pStream_c2 = fdopen(pPipe_c2c[STDOUT], "w")) == (FILE *) NULL)
	{
		Bailout("Cannot open pipe for writing!");
	}

	if(fprintf(pStream_c2,"%s\n", buffer) < 0)
	{
		Bailout("Cant write to pipe!");
	}

	FreeResources_c1();
	FreeResources_c2();
}

void ChildProcess_c2(void)
{
	int a,b,c;

	char buffer[MAXCHAR +1];

	if (close(pPipe_c2c[STDOUT]) == -1)
	{
		Bailout("Error closing the write descriptor!");
	}

	if ((pStream_c2 = fdopen(pPipe_c2c[STDIN], "r")) == (FILE *) NULL)
	{
		Bailout("Cannot open pipe for reading!");
	}

	fgets(buffer, MAXCHAR, pStream_c2);
	if(aus==1)
	{
		printf("Kind2 : erhalten: %s", buffer);
	}

	srand(time(NULL)+3);
	a=rand()%(strlen(buffer)-1);
	srand(time(NULL)+4);
	c=rand()%2;
	srand(time(NULL)+5);
	if(c<1)
	{
		b=(rand()%26)+65;

	}
	if(c==1)
	{
		b=(rand()%26)+97;

	}
	buffer[a]=b;

	if(aus==1)
	{
		printf("Kind2 : ENDE    : %s", buffer);
	}


	if(aus==0)
	{
		printf("%s", buffer);
	}

	FreeResources_c1();
	FreeResources_c2();
}

Dir fehlen noch viele Kommentare, und - wenn sie ähnlich streng sind - die Überprufung auf Fehler von printf, fgets, strcpy

that

Moderator
Hoffnungsloser Optimist
Avatar
Registered: Mar 2000
Location: MeidLing
Posts: 11326
Zitat von DirtyHarry
Dir fehlen noch viele Kommentare, und - wenn sie ähnlich streng sind - die Überprufung auf Fehler von printf, fgets, strcpy

Bei printf ist es noch am wenigsten schlimm, aber NIEMALS macht man sowas (am besten nichtmal bei privaten 5-Minuten-Hacks, aber sicher nicht bei Übungen - wenn man eine positive Bewertung erwartet - und auf keinen Fall bei echten Programmen):

Code:
strcpy(eingabe, argv[1]);

Genau solche Fehler haben zur Verbreitung von Viren, Würmern und anderer Malware geführt. Niemals darf man Eingaben mit unbekannter Länge in einen Puffer von begrenzter Länge kopieren.

muene

Addicted
Avatar
Registered: Jan 2004
Location: @Home
Posts: 430
Danke für die vielen Antworten. Funktioniert jetzt einwandfrei.

Bzgl strcpy: werd es gegen strncpy austauschen. Muss sowieos noch Kommentare schreiben und die oben schon erwähnten Überprüfungen von printf, fgets, ... .

Nochmals herzlichen Dank an alle.

Lg
Kontakt | Unser Forum | Über overclockers.at | Impressum | Datenschutz