Process

向暫停的父程序發送信號並保證它會在父程序暫停後到達

  • November 13, 2020

我有這種虛擬碼,我想知道我必須改變什麼,以保證發送給父母的信號確實會在父母暫停之後到達。

int main()
{
   int pid;
   
   for(int i = 0; i < 5; i++)
   {
       if((pid = fork()) == 0)
       {   
           mapp(i);
       }
   }

   for(int i = 0; i < 5; i++)
   {
       /*Parent opens fifo i for reading*/
       pause(); /*Parent must stop it's execution until child i writes to fifo i*/
       /*Parent reads from the fifo number i => SUCCESS*/ 
   }
   
   
}

void mapp(int i)
{
   /*Children opens fifo i for writing*/
   /*Children writes to fifo i*/
   kill(getppid(), SIGCONT); /*Children notifies it's father so that he's now be able to read*/
}

看起來邏輯沒有錯吧?但遺憾的是,程序並不總是按預期執行:有時執行會掛起,因為有時(並非總是)在父級甚至暫停之前發送信號,所以當父級暫停時,程序將掛起,因為它不會接收任何其他類型的信號。

PD:sleep()不是一個選項,我不能延長程序的執行時間。

謝謝!

你是對的,你的程序受制於競爭條件。

這裡的解決方案是在父程序中創建通信管道,而不是讓每個程序創建並連接它們。您提到他們使用fifos,但是fifo文件就像管道一樣,而且由於它們是家庭,您可能不需要fifo,管道就足夠了。

非常粗略:

#define CHILDREN 5
int main()
{
   int pid;
   int pipes[CHILDREN][2];
   
   for(int i = 0; i < CHILDREN; i++)
   {
       if (pipe(pipes[i]) == -1) {
          // Error
       ]
       
       pid = fork();
       if(pid == -1) {
         // Error
       } else if (pid == 0) {
           // Child   
           close(pipes[i][0]);
           mapp(i, pipes[i][1]);
       } else {
           // Parent
           close(pipes[i][1]);
       }
   }

   for(int i = 0; i < CHILDREN; i++)
   {
       /*Parent reads from the pipe number i => SUCCESS*/ 
       read(pipes[i][0], ...); // Will block until children writes
   }
   
   
}

void mapp(int i, int fd)
{
   /*Children writes to its pipe */
   write(fd, "hello Dad!\n", 11);
}

父級將阻塞,直到它可以從管道中讀取,所以它是完全有效的。如果你想阻塞直到它可以從任何管道讀取,你也可以這樣做,使用 select、epoll 等。

假設它們小於 PIPE_BUF(在 Linux 上,即 4096 字節),對管道的寫入是原子的。在最近的 Linux 上,您也可以使用 O_DIRECT 並擁有“數據包”模式。儘管由於您每個孩子都有一個管道,但這似乎是不必要的。

引用自:https://unix.stackexchange.com/questions/619373