1

I need to use SIGUSR1 and SIGUSR2 and read some text from pipe. One thread must read odd symbols, and another one must read even symbols. Main thread opens a .txt file and writes info into pipe, and 2 threads read symbols from pipe and write to their .txt files. I tried to use sigwait, but it looks like it doesn't work correctly. Any ideas? Thank you very much)

#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <printf.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <cerrno>
#include <signal.h>
#include <fcntl.h>
using namespace std;
static bool a=false;
static int c;

main(int argc, char** argv)
{
    int fildes[2]; 
    char ch,ch1,ch2;
    FILE *fp,*f1,*f2;
    int stat,sig;

    sigset_t set1;
    sigset_t set2;
    sigemptyset(&set1);
    sigemptyset(&set2);
    sigaddset(&set1,SIGUSR1);
    sigaddset(&set2,SIGUSR2);
    sigprocmask(SIG_BLOCK,&set1,NULL);
    sigprocmask(SIG_BLOCK,&set2,NULL);

    pid_t p1,p2;
    pipe(fildes); 
    cout<<argv[1]<< " " <<argv[2]<< " " <<argv[3]<<endl;
    fp=fopen(argv[1],"r"); 
    f1=fopen(argv[2],"a");
    f2=fopen(argv[3],"a");
    int chet=2;
    p1=fork();
    if (!p1)
    { 
        do
        {     
            sigwait(&set1,&sig);
            read(fildes[0], &ch1, 1);
            printf("%c",ch1);
            fprintf(f1,"%c",ch1);

        }
        while(!a); 
        exit(0);
    }
    p2=fork();
    if (!p2)
    { 
           do
           {     
                sigwait(&set2,&sig);
                read(fildes[0], &ch2, 1);
                printf("%c",ch2);
                fprintf(f2,"%c",ch2);

           }
           while(!a); 
           exit(0);
    }
    else
    {
        while(!feof(fp))
        {  
              ch=fgetc(fp);
              write(fildes[1],&ch,1);
              if(chet%2==0)
                  kill(p1,SIGUSR1);
                else kill(p2,SIGUSR2);
              chet++;
              //sleep(1/10);
        }
        a=true;

        wait(&stat); 
        close(fildes[0]); 
        close(fildes[1]);
        fclose(f1);
        fclose(f2);
        fclose(fp); 
    }
}
pilcrow
  • 51,771
  • 11
  • 83
  • 128
JeSa
  • 419
  • 4
  • 10
  • 1
    Whay exactly happens? Looks like it doesnt work correctly is not enough information – user2717954 Nov 22 '14 at 16:16
  • One thing is wrong in your code: It doesn't have any error handling. Zero. – Ulrich Eckhardt Nov 22 '14 at 16:20
  • I gave him the credit that he removed error handling code from the question to make it more readable – user2717954 Nov 22 '14 at 16:25
  • @user2717954, nothing happens, if wait() function is not commented, program waits all the time, and if I comment it, program ends, and if I add something like kill(p2,SIGUSR2); in second fork, it shows me my text, but ALL text, nor odd or even symbols, so with information is OK – JeSa Nov 22 '14 at 16:38

1 Answers1

0

sigwait and so forth work perfectly well.

However, you have two "classic" problems here: first, an assumption of synchronized behavior that doesn't hold, and, second, buffering.

Unsynchronized processes:

First, for example, on my system, given a five byte input file, the parent process writes all bytes (including an EOF marker — whoops!) and sends all signals before either child process even calls sigwait:

[parent] read(5, "BaRd\n", 4096)     = 5
[parent] write(4, "B", 1)            = 1
[parent] kill(5404, SIGUSR1)         = 0
[parent] write(4, "a", 1)            = 1
[parent] kill(5405, SIGUSR2)         = 0
[parent] write(4, "R", 1)            = 1
[parent] kill(5404, SIGUSR1)         = 0
[parent] write(4, "d", 1)            = 1
[parent] kill(5405, SIGUSR2)         = 0
[parent] write(4, "\n", 1)           = 1
[parent] kill(5404, SIGUSR1)         = 0
[parent] read(5, "", 4096)           = 0
[parent] write(4, "\377", 1)         = 1                        # Oops! we wrote stdio's EOF marker
[parent] kill(5405, SIGUSR2)         = 0
[parent] wait4(-1,  <unfinished ...>
[child2] rt_sigtimedwait([USR2], NULL, NULL, 8) = 12            # Oops! child2 is going first
[child2] read(3, "B", 1)             = 1
[child2] rt_sigtimedwait([USR2], NULL, NULL, 8 <unfinished ...> # Oops! ordinary UNIX signals don't queue
[child1] rt_sigtimedwait([USR1], NULL, NULL, 8) = 10
[child1] read(3, "a", 1)             = 1
[child1] rt_sigtimedwait([USR1], NULL, NULL, 8

The children are not guaranteed to be ready as soon as you call fork(). Moreover, it is not guaranteed that child1 will accept its signal first. Indeed, in the above, it is child2 who accepts a signal and read()s first. (Another complicating factor here is that conventional UNIX signals do not queue. So, child1 will accept only one SIGUSR1, unaware of any previous redundant signals.)

Buffering:

I'm inferring that your second problem is that you see no output from the children, neither to the terminal nor to their output files. This is simply a mismatch between your expectations and those output streams' default buffering. Change the buffering, or explicitly flush them, and you'll see that each child writes at least one byte.

Community
  • 1
  • 1
pilcrow
  • 51,771
  • 11
  • 83
  • 128