Performance Problem: dier Code frisst 100% CPU Zeit...



  • Hi,

    das ist erstma nur zum testen....

    //User includes
    #include "main.h"
    //system includes
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    #include <string.h>
    
    using namespace std;
    
    int App1_pid = 0;
    int App2_pid = 0;
    
    const char* App1path = "/home/user1/workspace/App1/App1";
    const char* App2path = "/home/user1/workspace/App2/App2";
    
    pipe_type App1_Pipe;
    pipe_type App2_Pipe;
    
    int run_executable( pipe_type &child_pipe,
    					const char* progname,
    					int &child_pid )
    {
    	if( pipe( child_pipe.pipe_stdin.pipe_fd ) == -1) {
    		perror( "pipe" );
    	}
    	//init stdin stream
    	PIPE_READ_END( child_pipe.pipe_stdin.fnctl_flags ) =
    			fcntl( PIPE_READ_END( child_pipe.pipe_stdin.pipe_fd ),
    				   F_GETFL );
    	fcntl( PIPE_READ_END( child_pipe.pipe_stdin.fnctl_flags ),
    		   F_SETFL,
    		   PIPE_READ_END( child_pipe.pipe_stdin.fnctl_flags ) | O_NONBLOCK );
    
    	if( pipe( child_pipe.pipe_stdout.pipe_fd ) == -1) {
    		perror( "pipe" );
    	}
    
    	//init stdout stream
    	PIPE_READ_END( child_pipe.pipe_stdout.fnctl_flags ) =
    			fcntl( PIPE_READ_END( child_pipe.pipe_stdout.pipe_fd ),
    				   F_GETFL );
    	fcntl( PIPE_READ_END( child_pipe.pipe_stdout.fnctl_flags ),
    			   F_SETFL,
    			   PIPE_READ_END( child_pipe.pipe_stdout.fnctl_flags ) | O_NONBLOCK );
    
    	if( pipe( child_pipe.pipe_stderr.pipe_fd ) == -1) {
    		perror( "pipe" );
    	}
    
    	//init stderr stream
    	PIPE_READ_END( child_pipe.pipe_stderr.fnctl_flags ) =
    			fcntl( PIPE_READ_END( child_pipe.pipe_stderr.pipe_fd ),
    				   F_GETFL );
    	fcntl( PIPE_READ_END( child_pipe.pipe_stderr.fnctl_flags ),
    		   F_SETFL,
    		   PIPE_READ_END( child_pipe.pipe_stderr.fnctl_flags ) | O_NONBLOCK );
    
    	int pid = vfork();
    	if( pid == -1 ) {
    		perror("fork");
    		exit( EXIT_FAILURE );
    	}
    	else if(pid == 0){
    		child_pid = getpid();
    		close( PIPE_WRITE_END( child_pipe.pipe_stdin.pipe_fd ) );
    		close( PIPE_READ_END( child_pipe.pipe_stdout.pipe_fd ) );
    		close( PIPE_READ_END( child_pipe.pipe_stderr.pipe_fd ) );
    
    		dup2( PIPE_READ_END( child_pipe.pipe_stdin.pipe_fd ), STDIN_FILENO );
    		dup2( PIPE_WRITE_END( child_pipe.pipe_stdout.pipe_fd ), STDOUT_FILENO );
    		dup2( PIPE_WRITE_END( child_pipe.pipe_stderr.pipe_fd ), STDERR_FILENO );
    
    		execl( progname, progname, (char*) 0 );
    		_exit(1);
    	}
    	else if( pid > 0 ){
    		close( PIPE_READ_END( child_pipe.pipe_stdin.pipe_fd ) );
    		close( PIPE_WRITE_END( child_pipe.pipe_stdout.pipe_fd ) );
    		close( PIPE_WRITE_END( child_pipe.pipe_stderr.pipe_fd ) );
    	}
    	return 0;
    }
    
    int read_pipebuffer( char* buff, int &no_bytes, int pipe_fd )
    {
    	char tmpBuff[ MAX_BUFFER ] = {0};
    	int i;
    	size_t bytesread = 0;
    	fd_set fds;
    	struct timeval tv;
    
    	tv.tv_sec = tv.tv_usec = 0;
    	FD_ZERO( &fds );
    	FD_SET( pipe_fd, &fds);
    	int rv = select( pipe_fd + 1, &fds, NULL, NULL, &tv );
    	if( rv == -1 )
    		perror("select");
    	else if ( rv > 0 ){
    		if( FD_ISSET( pipe_fd, &fds ) )
    		{
    			bytesread = read( pipe_fd,
    							  tmpBuff,
    							  sizeof( tmpBuff ) );
    			no_bytes = bytesread;
    			if( bytesread == 0 )
    			{
    				return -1;
    			}
    		}
    	}
    	if(bytesread > 0 ){
    		if( strlen( tmpBuff ) > 0 ){
    			sprintf( buff, "%s",  tmpBuff );
    			tmpBuff[ MAX_BUFFER ] = 0;
    		}
    	}
    	FD_CLR( pipe_fd, &fds );
    	return 0;
    }
    
    int main()
    {
    	char buff[ MAX_BUFFER ];
    	int status;
    	cout << "Ok, jetzt gehts los." << endl;
    
    	while (1)
    	{
    		if( App1_pid == 0 )
    		{
    			run_executable( App1_Pipe, App1path, App1_pid );
    		}
    		int no_bytes = 0;
    		bzero( buff, sizeof( buff ) );
    		if( App1_pid > 0 ){
    			read_pipebuffer( buff,
    							 no_bytes,
    							 PIPE_READ_END(App1_Pipe.pipe_stdout.pipe_fd) );
    		}
    		if( no_bytes > 0 ){
    			char *pWord = NULL;
    			pWord = strstr( buff, "Hello");
    			if(pWord){
    				if( App2_pid == 0 )
    				{
    					run_executable( App2_Pipe, App2path, App2_pid );
    				}
    
    			}
    			pWord = NULL;
    
    			pWord = strstr( buff, "kill App1");
    			if( pWord ){
    				if( App1_pid ){
    					kill( App1_pid, SIGKILL );
    					printf("App1 terminated!");
    					pid_t  w;
    					do {
    					    w = waitpid(App1_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));
    					App1_pid = 0;
    				}
    
    			}
    
    			pWord = NULL;
    			printf("%s\n", buff);
    		}
    		bzero( buff, sizeof( buff ) );
    		if( App2_pid > 0 ){
    			read_pipebuffer( buff,
    							 no_bytes,
    							 PIPE_READ_END(App2_Pipe.pipe_stdout.pipe_fd) );
    		}
    		if( no_bytes > 0 ){
    			printf("%s\n", buff);
    		}
    
    	}
    	return 0;
    }
    
    #define PIPE_READ_END(x) x[0]
    #define PIPE_WRITE_END(x) x[1]
    
    typedef enum{
    	acc_read  = 0,
    	acc_write = 1
    } pipe_access_type;
    
    #ifndef MAIN_H_
    #define MAIN_H_
    
    #define MAX_PIPE_FD 2
    #define MAX_BUFFER 257
    
    typedef struct
    {
    	int pipe_fd[ MAX_PIPE_FD ];
    	int fnctl_flags [ MAX_PIPE_FD ];
    	pipe_access_type pipe_access;
    }
    	pipe_stdin_type,
    	pipe_stdout_type,
    	pipe_stderr_type;
    
    typedef struct{
    	pipe_stderr_type pipe_stderr;
    	pipe_stdin_type pipe_stdin;
    	pipe_stdout_type pipe_stdout;
    } pipe_type;
    
    int run_executable( pipe_type &child_pipe,
    					const char* progname,
    					int &child_pid );
    
    int read_pipebuffer( char* buff, int &no_bytes, int pipe_fd );
    
    #endif /* MAIN_H_ */
    

    App1...

    #include "main.h"
    
    #include <iostream>
    
    using namespace std;
    
    int main(){
    
    	while(1){
    		cout << "******Hello" << endl;
    		sleep(10);
    		cout << "******App1" << endl;
    		sleep(10);
    		cout << "******kill App1" << endl;
    		sleep(10);
    		cout << "******Yeah" << endl;
    	}
    	return 0;
    }
    

    App2...

    #include "main.h"
    
    #include <iostream>
    
    using namespace std;
    
    int main(){
    	while(1){
    		cout << "******HI!!!!!" << endl;
    		sleep(40);
    		cout << "******App2" << endl;
    	}
    	return 0;
    }
    

    Gruß
    Franky



  • Naja, bei einem

    tv.tv_sec = tv.tv_usec = 0;
    

    kehrt select sofort zurück...
    und die äußere while(1)-Schleife macht den Rest.
    Probier mal

    tv.tv_sec = tv.tv_usec = 1;
    

    PS:
    Liefert vfork() nicht undefiniertes Verhalten, wenn danach im Kind kein exec* nachfolgt ?
    Also sollte da nicht ein normales fork() stehen ?

    lg XOR 😉



  • xor schrieb:

    Naja, bei einem

    tv.tv_sec = tv.tv_usec = 0;
    

    kehrt select sofort zurück...
    und die äußere while(1)-Schleife macht den Rest.
    Probier mal

    tv.tv_sec = tv.tv_usec = 1;
    

    Ok, werd ich mal machen.....bis gleich.

    xor schrieb:

    PS:
    Liefert vfork() nicht undefiniertes Verhalten, wenn danach im Kind kein exec* nachfolgt ?
    Also sollte da nicht ein normales fork() stehen ?

    lg XOR 😉

    mit vfork...
    1.)

    pid = vfork();
    //das kind 
    if( pid == 0){
    ....
    }
    //der Vater
    if( pid > 0){
    ...
    }
    //nur der Vater....
    ...
    ...
    

    den mit fork...
    2.)

    pid = fork();
    //das kind 
    if( pid == 0){
    ....
    }
    //der Vater
    if( pid > 0){
    ...
    }
    //das Kind und  der Vater....
    ...
    ...
    

    würde dann nicht mit fork die while im Kind als auch im Vater laufen?

    Gruß



  • Ich beziehe mich mit vfork auf seine Beschreibung

    The vfork() function has the same effect as fork(), except that the behaviour is undefined if the process created by vfork() either modifies any data other than a variable of type pid_t used to store the return value from vfork(), or returns from the function in which vfork() was called, or calls any other function before successfully calling _exit() or one of the exec family of functions.

    Soweit ich weiß muss fork() den gesamten Prozess duplizieren, während vfork() dies nicht zwingend machen muss, weil unmittelbar danach eine exec* den Prozess neu lädt oder eben exit() folgen muss. vfork() kann aus einem Prozess zwei machen, die den gleichen Speicher benutzen (geht sehr schnell), weil einer der beiden Prozesse garantiert, dass er sich selbst durch den Aufruf von exec* wieder einen neuen Speicher sucht und den anderen nicht verändert. In deinem Code veränderst du aber nach vfork() Variablen und rufst System-Funktionen auf ... das wiederspricht eben der vfork-Definition.

    pid = fork(); // oder vfork();
    //das kind
    if( pid == 0){
      ....
      exec*(...); // Kind ist jetzt ein anderes Programm und wird hier nicht mehr zurückspringen
    }
    //der Vater
    if( pid > 0){
      ...
    }
    //  nur noch der Vater
    

    PS: Ich gestehe aber selber vfork noch nie aktiv eingesetzt zu haben (eben wegen seiner Eigenschaften und weil ich immer noch etwas anderes vor exec zu tun hatte). Es ist auch bekannt dass auf manchen Systemen vfork() == fork() ist und somit keine Seiteneffekte hat ... man kann sich eben nur nicht darauf verlassen 😉

    lg XOR



  • Hi,

    ja, aber wie stelle ich den sicher, das der nachfolgende Code nur vom Vater ausgeführt wird? Also "nur der Vater..." und nicht "Vater und Kind"... oder habe ich da was nicht verstanden?

    Gruß



  • FrankTheFox schrieb:

    ja, aber wie stelle ich den sicher, das der nachfolgende Code nur vom Vater ausgeführt wird? Also "nur der Vater..." und nicht "Vater und Kind"...

    Indem Du das Kind rechtzeitig beendest?



  • The exec family of functions shall replace the current process image with a new process image. The new image shall be constructed from a regular, executable file called the new process image file. There shall be no return from a successful exec, because the calling process image is overlaid by the new process image.

    Wenn dein Programm exec aufruft und dieser Aufruf erfolgreich war, ist dein ursprüngliches (Kind-)Programm bereits beendet, weil exec deinen Prozess durch den neu geladenen ersetzt hat. Nur PID bleibt gleich (damit du im Vater zB. darauf warten kannst bis das andere Programm beendet ist).

    pid = fork();
    if(pid == 0)
    {
      exec*(...);
      printf("exec failed"); // wird nur ausgeführt wenn exec fehlschlägt
      exit(1);
    }
    


  • Hi,

    ja, ich hatte gesehen, das folgendes möglich ist:

    PC could be executed by both parent and child.
    Das hatte ich vermeiden wollen....

    //"Sane Structured" use of a fork() call.
         #include <sys/types.h>
         #include <unistd.h>     
         int main() {
         pid_t	pid;
         ... code P_B
         if((pid = fork()) > 0) {   /* Parent process */
           ... code P_A
         } else if (pid == 0) {     /* Child process */
           ... code C_A
         } else {                   /* Parent process, fork() failed */
           ... code P_AE
         }
         ... code PC
         }
    
    /*
    You should always use a fork() in the above structured manner
    to avoid as many problems as possible. Concurrent programs are
    very hard to get correct and to debug compared to non-parallel
    programs. In the above pseudo code:
    
    Code:
      P_B (Before fork) is only executed by the parent (child does not exist yet).
      P_A (After fork) is only executed by the parent (child now exists)
      C_A (After fork) is only executed by the child.
      P_AE (After fork, that had an Error) is only executed by the parent
          if the fork had an error (no child exists).
      PC could be executed by both parent and child. It is "bad" practice
         to have a child ever leave code C_A and execute code PC. 
         The child should either make an exec() call in code C_A or
         an exit() call.
    */
    

    Aber dank eurer Hilfe und de Seite auf der eigentlich das gleiche gesagt wurde, ist der fork mit einem exec die Garantie, as PC nicht eintritt.

    Danke!


Anmelden zum Antworten