signals in linux c programing

I am programing a system with 3 processes, Judge , Player 1 , and player 2 .

I use signal kill(playerPid,SIGUSR1) for the judge to wake up a player on his turn, and a signal kill(judge,SIGHUP) to wake up the judge after a turn is complete.

after each kill signal i use a pause() so the process wont continue. the problem is sometimes after a kill signal for example from player to judge , the judge wakes up before the player is doing his pause() . and the next time the judge will wake up this player he will pause and my program will be stack because all 3 processes are in a pause state with no one to wake them up.

so my question is: what is supposed to happen after a kill command?

1 . the current process continuous until the pause(), and then goes to the process he signaled. for example:

 kill(judge, SIGHUP);
    //stops here and goes to the judge.      
 pause();

this is what sometimes happens in my code and i get stuck with all processes on pause() .

2 . the current process stops and goes to the process he just signaled to. for example:

kill(judge, SIGHUP);
pause();
//stops here and going to the judge.

**this is what most of the time happening in my code.

in my code the behavior changes, sometimes its like number 1 and sometimes like number 2.

what am i doing wrong?

is it possible for the process to wake up before the handler function who received the signal finished running?

Or is it possible for a process to pause after a kill signal, before getting to the pause line? if so why and how do i handle this?

here is my code:

 ///////////////////////signal handlers

void sigHandler(int signo)
{
    printf("Received signal %dn", signo);

    if(signo == SIGHUP )//fatehr gets it from son
    {
        signal(SIGHUP ,sigHandler);
        printf("son woke up fathern");
    }
    else if (signo == SIGUSR1)//son gets it from father
    {
        signal(SIGUSR1, sigHandler);
        printf("Judge waking player Bn");
    }
    else if (signo == SIGUSR2)//father gets it from son
    {
        signal(SIGUSR2, sigHandler);
        printf("Judge waking player An");
    }
    else if (signo == SIGTERM)//son get it when father kill them
    {
        signal(SIGTERM, sigHandler);

        printf("%d im deadn", getpid());
        kill(getppid(), SIGUSR2);

        exit(1);
    }
    else if (signo == SIGINT)//father get it to play round with ^C
    {
        signal(SIGINT, sigHandler);

        printf("play round!!!!!!!!!!!!n");
    }
}

void sigHandler2(int signo)
{
    if (signo == SIGINT)//son get it to play round with ^C
    {
        signal(SIGINT, sigHandler2);
    }
}


void wakePlayer(int player,int turn, int* boardPtr)
{
    boardPtr[27] = 0;
    while (boardPtr[27] != 1)//while player didnt finish his turn
    {
        if (turn==1)
            kill(player, SIGUSR1);
        else
            kill(player, SIGUSR2);
        pause();
    }

}


///////////////////////End of signal handlers
int main(){

    int j = 1;;
    int player1;
    int player2;
    int judge;
    time_t t;
    key_t key;
    int   shmid;
    int  *boardPtr;
    judge = getpid();
    srand(time(NULL) *(5));

    shmid = createShm(&boardPtr);//creating shm
    boardPtr[1] = 2;


    player1 = fork();//create player 1
    if (player1 == -1)
    {
        printf("error in fork");
        exit(1);
    }
    if (player1>0)//not player 1
    {
        player2 = fork();//create player 2
        if (player2 == -1)
        {
            printf("error in fork");
            exit(1);
        }
        if (player2>0)//This is The Judge!********************************************************************************
        {
            signal(SIGHUP, sigHandler);//signal from player after he did his turn
            signal(SIGINT, sigHandler);//catch the ^c to make the next turn
            printf("father startedn");
            while(boardPtr[1]!=0)//Players didnt set up their handlers
            {
                sleep(1);       
            }
            printf("father initiatingn");
            initiation(boardPtr, player1, player2);//create the board and choose a player to start

            printBoard(boardPtr, 0);//print the current board.

            while (checkWin(boardPtr) == 0)//while no one won.
            {
                if (boardPtr[26] == 1)//if it is player "b" turn.
                    wakePlayer(player1,1, boardPtr);
                else //if it is player "a" turn.    
                    wakePlayer(player2,2, boardPtr);

                //pause();
                printBoard(boardPtr, j);//print the current board.
                boardPtr[26] = (boardPtr[26] * 2) % 3;//change turns
                j++;
            }

            printf("game finished!n");
            killItWithFire(player1, player2, shmid, &boardPtr);//cleaning up after match.
            printf("Judge is suiciding, goodbye!n");
            exit(1);
        }
        else if (player2 == 0)//this is player 2!******************************************************************************
        {
            signal(SIGUSR2, sigHandler);//signal from judge to make a turn
            signal(SIGTERM, sigHandler);//signal from judge to terminate
            signal(SIGINT, sigHandler2);//get the ^c and pause.
            printf("%d player A startedn", getpid());

            boardPtr[1]--;//mark player A handlers are set.
            pause();
            while (1)
            {
                int r = roll(1);
                printf("%d player A threw a %dn", getpid(), r);
                if (boardPtr[22] == 0)//checking if it is an initation round
                {
                    boardPtr[21] = r;
                }
                else
                {
                    turn(2, r, boardPtr);//makes a turn
                }
                boardPtr[27] = 1;//mark that i finished my turn.
                kill(judge, SIGHUP);//signal to judge after turn.  
                pause();



            }

        }
    }
    else//this is player 1!**********************************************************************************************
    {

        signal(SIGUSR1, sigHandler);//signal from judge to make a turn
        signal(SIGTERM, sigHandler);//signal from judge to terminate
        signal(SIGINT, sigHandler2);//signal to pause when player gets a ctrl C
        printf("%d player B startedn", getpid());

        boardPtr[1]--;//mark player A handlers are set.
        pause();
        while (1)
        {           
            int r = roll(2);
            printf("%d player B threw a %dn", getpid(), r);
            if (boardPtr[22] == 0)//flag to check if it is an initiation round.
            {
                boardPtr[20] = r;
            }
            else
            {
                turn(1, r, boardPtr);//player b makes a turn
            }
            boardPtr[27] = 1;//marks that player B finished his turn. 
            kill(judge, SIGHUP);//signal to judge after turn.  
            pause();

        }

    }
    return 0;
}

用这样的东西替换每个杀/暂停对

/* These flags are set in the interrupt handler, therefore we should
   declare them volatile, so that the compiler can anticipate that
   they can be changed outside the normal program flow */
volatile int sigusr1_flag, sigusr2_flag;

void sighandler(int signo) {
  if(signo == SIGUSR1)
    sigusr1_flag = 1;
  if(signo == SIGUSR2)
    sigusr2_flag = 1;
}

void kill_and_wait(pid_t pid, int signaltosend, int signaltowait, volatile int *flag) {
  sigset_t mask, savemask;
  /* Create a signal set with only one element */
  sigemptyset(&mask);
  sigaddset(&mask, signaltowait);
  /* Block the signal that we are expecting back from the other process,
     so if it arrives right after the kill(), it will be put "on hold",
     and delivered first when it's unblocked. The active signal set is
     saved to savemask, we'll use it later to temporarily unblock the
     signal that we are expecting. */
  sigprocmask(SIG_BLOCK, &mask, &savemask);
  /* Clear the flag that would be set when the response signal has arrived */
  *flag = 0;
  /* Now we can safely send our signal. */
  kill(pid, signaltosend);
  /* Repeat until the flag is set in the interrupt handler. We do this 
     because some other signal could arrive here that we would otherwise
     ignore, but it wakes up our process early. */
  while(!*flag) {
    /* It sets the mask of blocked signals temporarily to savemask, which
       was the state when we entered ths funcion, effectively unblocking
       signaltowait, then waits for any signal to arrive. */
    sigsuspend(&savemask);
  }
  /* restore the original signal mask */
  sigprocmask(SIG_UNBLOCK, &mask, NULL);
}
链接地址: http://www.djcxy.com/p/50026.html

上一篇: SIGSTOP / SIGCONT POSIX行为

下一篇: 在linux c编程中的信号