Daemon mit zwei Aufgaben...



  • Hi,

    ich habe eine Linux Dienst programmiert, der die Aufgabe hat, eine serielle Schnittstelle zu überwachen, auszulesen und die Daten zu verarbeiten.
    Das funktioniert auch sehr gut! Nun soll aber parallel noch ein TCP Server Port aufgemacht werden, der schön wartet und wenn er einen Befehl bekommt, Daten als XML ausgeben. XML und TCP Dienst sind geschrieben. Nur leider werden die beiden Prozesse nicht parallel verarbeitet.

    So habe ich den Dienst aufgebaut.

    Instanzierung:

    /* build a daemon */
    void daemonize()
    {
        int i,lfp;
        char str[10];
    	if(getppid()==1) return; /* already a daemon */
    	i=fork();
    	if (i<0) exit(1); /* fork error */
    	if (i>0) exit(0); /* parent exits */
    	/* child (daemon) continues */
    	setsid(); /* obtain a new process group */
    	for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors */
    	i=open("/dev/null",O_RDWR); dup(i); dup(i); /* handle standart I/O */
    	umask(027); /* set newly created file permissions */
    	chdir(LOG_DIR); /* change log/pid directory */
    	lfp=open(PID_FILE,O_RDWR|O_CREAT,0640);
    	if (lfp<0) exit(1); /* can not open */
    	if (lockf(lfp,F_TLOCK,0)<0) exit(0); /* can not lock */
    	/* first instance continues */
    	sprintf(str,"%d\n",getpid());
    	write(lfp,str,strlen(str)); /* record pid to lockfile */
    	signal(SIGCHLD,SIG_IGN); /* ignore child */
    	signal(SIGTSTP,SIG_IGN); /* ignore tty signals */
    	signal(SIGTTOU,SIG_IGN);
    	signal(SIGTTIN,SIG_IGN);
    	signal(SIGHUP,signal_handler); /* catch hangup signal */
    	signal(SIGTERM,signal_handler); /* catch kill signal */
    }
    

    In der main arbeite ich mit einer while-Schleife.

    while (STOP==FALSE) 
    {
    
      /* serielle Verarbeitung
      *  
      *
      *
      */
    
      if (buffer[0]=='z') STOP=TRUE;
    }
    close(sockfd);
    

    Mein TCP Server sieht so aus:

    void StartTCPServer(void)
    {
        int listenfd,sockfd,n;
        struct sockaddr_in servaddr,cliaddr;
        socklen_t clilen;
        pid_t     childpid;
        char mesg[1000];
    
        listenfd=socket(AF_INET,SOCK_STREAM,0);
    
        bzero(&servaddr,sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
        servaddr.sin_port=htons(81);
        bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
    
        listen(listenfd,1024);
    
        for(;;)
        {
            clilen=sizeof(cliaddr);
            sockfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);
    
            if ((childpid = fork()) == 0)
            {
                close (listenfd);
    
                for(;;)
                {
                    n = recvfrom(sockfd,mesg,1000,0,(struct sockaddr *)&cliaddr,&clilen);
                    log_message(LOG_FILE,mesg);
                    if (strstr(mesg, "GET / HTTP") != NULL)
                        sendto(sockfd,XMLString,sizeof(XMLString),0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
                    mesg[n] = 0;
                }
    
            }
            close(sockfd);
        }
    }
    

    Wie kann ich den starten, sodass er meinen eigentlichen Prozess in der "main while" Schleife nicht stoppt?

    Vielen Dank im Voraus!

    Nico



  • Entweder non-blocking socket oder thread verwenden



  • pferdefreund schrieb:

    Entweder non-blocking socket oder thread verwenden

    Ich habe es mit pthread_create gelöst. Danke



  • skynet74 schrieb:

    Ich habe es mit pthread_create gelöst. Danke

    Nun, wenn du das ganze so einfach mit pthread_create lösen konntest, stellt sich mir die Frage, ob die beiden Aufgaben überhaupt in den gleichen Prozess gehören und wenn, ob das Ergebnis wirklich richtig ist. Welche Daten teilen sich die beiden Threads? Hast du den Zugriff auf diese Daten ordentlich synchronisiert?

    Das kannst du u.U mit dem ThreadSanitizer[1] (benötigt GCC 4.8 oder LLVM/Clang 3.2, dann mit-fsanitze=thread als PIE kompilieren) herausfinden. Valgrind hat auch ein paar Checker, die solche Probleme aufdecken können.

    [1] http://code.google.com/p/thread-sanitizer/



  • Die beiden Theads teilen sich 10 kleine Variablen. Diese werden vom ersten Thread von der seriellen Schnittstelle ausgelesen und in einem XML String zusammengesetzt und der 2. Thread gibt dies auf Port XX aus. Die Variablen ändern sich alle 2 Sekunden.

    Ich habe das PTHREADING nach dem Vorbild umgesetzt:

    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <assert.h>
    
    #define NUM_THREADS     5
    
    void *TaskCode(void *argument)
    {
       int tid;
    
       tid = *((int *) argument);
       printf("Hello World! It's me, thread %d!\n", tid);
    
       /* optionally: insert more useful stuff here */
    
       return NULL;
    }
    
    int main(void)
    {
       pthread_t threads[NUM_THREADS];
       int thread_args[NUM_THREADS];
       int rc, i;
    
       /* create all threads */
       for (i=0; i<NUM_THREADS; ++i) {
          thread_args[i] = i;
          printf("In main: creating thread %d\n", i);
          rc = pthread_create(&threads[i], NULL, TaskCode, (void *) &thread_args[i]);
          assert(0 == rc);
       }
    
       /* wait for all threads to complete */
       for (i=0; i<NUM_THREADS; ++i) {
          rc = pthread_join(threads[i], NULL);
          assert(0 == rc);
       }
    
       exit(EXIT_SUCCESS);
    }
    

    Wirklich synchronisiert müssen beide nicht sein. Egal wer zuerst zuschlägt, es ist richtig 😃


Log in to reply