linux c中的信号编程

时间:2016-03-25 09:36:14

标签: c linux unix signals

我正在使用3个流程JudgePlayer 1player 2对系统进行编程。

我使用信号kill(playerPid,SIGUSR1)judge在他的回合中唤醒player, 并且在转弯完成后唤醒法官的信号kill(judge,SIGHUP)

每个kill signal后我使用pause(),因此流程不会继续。 问题有时是在kill signal之后,例如从playerjudgejudge会在玩家执行pause()之前醒来。 并且下次judge将唤醒此player时他将pause并且我的程序将被堆叠,因为所有3 processes都处于pause状态且没有一个人叫醒他们。

所以我的问题是: 杀戮命令后应该发生什么?

1 即可。当前进程一直持续到暂停(),然后进入他发出信号的过程。 例如:

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

这有时会发生在我的代码中,我会遇到pause()上的所有流程。

2 即可。当前流程停止并进入他刚刚发出信号的流程。 例如:

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

**这是我代码中大部分时间发生的事情。

在我的代码中,行为会发生变化,有时会像数字1一样,有时候就像数字2一样。

我做错了什么?

是否可以在收到信号的处理函数完成运行之前唤醒进程?

或者在进入暂停线之前,进程是否可以在终止信号后暂停?如果是这样,我为什么以及如何处理这个?

这是我的代码:

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

void sigHandler(int signo)
{
    printf("Received signal %d\n", signo);

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

        printf("%d im dead\n", 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 started\n");
            while(boardPtr[1]!=0)//Players didnt set up their handlers
            {
                sleep(1);       
            }
            printf("father initiating\n");
            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 started\n", getpid());

            boardPtr[1]--;//mark player A handlers are set.
            pause();
            while (1)
            {
                int r = roll(1);
                printf("%d player A threw a %d\n", 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 started\n", getpid());

        boardPtr[1]--;//mark player A handlers are set.
        pause();
        while (1)
        {           
            int r = roll(2);
            printf("%d player B threw a %d\n", 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;
}

1 个答案:

答案 0 :(得分:0)

用这样的

替换每个kill / pause对
/* 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);
}