일시 중지된 상위 프로세스에 신호를 보내고 상위 프로세스가 일시 중지된 후에 신호가 도착하도록 보장합니다.

일시 중지된 상위 프로세스에 신호를 보내고 상위 프로세스가 일시 중지된 후에 신호가 도착하도록 보장합니다.

나는 이 의사 코드를 가지고 있으며 부모에게 보낸 신호가 부모가 일시 중지된 후에 실제로 도착할 것이라는 것을 보장하기 위해 무엇을 변경해야 하는지 궁금합니다.

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()옵션이 아닙니다. 프로그램 실행 시간을 연장할 수 없습니다.

감사해요!

답변1

당신 말이 맞습니다. 당신의 프로그램은 경쟁 조건의 영향을 받습니다.

여기서 해결 방법은 각 프로세스에서 통신 파이프를 생성하고 연결하는 대신 상위 프로세스에서 통신 파이프를 생성하는 것입니다. fifo를 사용한다고 말씀하셨는데 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를 사용하고 "패킷" 모드를 사용할 수 있습니다. 모든 아이들은 파이프를 가지고 있었지만 그것은 불필요해 보였습니다.

관련 정보