Solaris 11.3에서 실행되는 다음 코드를 고려하십시오.
int main(void) {
pid_t pid = fork();
if (pid > 0) {
printf("[%ld]: Writing from parent process\n", getpid());
}
if (pid == 0) {
execl("/usr/bin/cat", "/usr/bin/cat", "file.c", (char *) 0);
perror("exec failed");
exit(1);
}
}
실행할 때마다 "write from parent" 줄이 항상 마지막에 출력됩니다. 내 학교 과제에서 자식 프로세스가 완료된 후에만 줄을 인쇄하도록 wait(2)를 사용하지 않았다면 이 결과에 놀라지 않을 것입니다. 왜 이런 일이 발생하며, 이 문제를 해결하기 위해 wait(2) 또는 waitpid(2)를 안전하게 사용할 수 있도록 하위 프로세스가 cat을 실행하기 전에(또는 순서가 최소한 정의되지 않은 경우) 이 줄이 인쇄되도록 하려면 어떻게 해야 합니까?
답변1
@AndrewHenle이 언급했듯이 특정 순서로 프로세스를 예약하기 위해 시스템에 의존하는 것은 안전하지 않으며 불합리합니다. 귀하의 경우처럼 일정이 일관된 것처럼 보이더라도 운영 체제 구현자가 스케줄러의 동작을 변경하는 것을 막을 수 있는 방법은 없습니다.
프로세스/스레드 간의 작업 순서가 관련된 경우 어떤 형태의 통신이 필요합니다.
귀하의 시나리오에서는 간단한 차단 읽기가 작업을 수행합니다. 포크 앞에 파이프를 만듭니다. 그런 다음 부모가 메시지를 인쇄한 후에만 부모의 파이프에 씁니다. 동시에 파이프에서 데이터를 읽으려는 하위 프로세스는 상위 프로세스가 쓸 때까지 실행을 차단합니다.
각 프로세스에서 오류 처리 및 사용되지 않는 파이프 파일 설명자(일반적으로 분기 후 명시적으로 닫힘)를 무시합니다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void) {
char buf[1];
int pipe_fds[2];
pipe(pipe_fds);
pid_t pid = fork();
if (pid > 0) {
printf("[%ld]: Writing from parent process\n", getpid());
write(pipe_fds[1], "_", 1);
wait(NULL);
}
if (pid == 0) {
read (pipe_fds[0], buf, 1);
execl("/usr/bin/cat", "/usr/bin/cat", "file.c", (char *) 0);
perror("exec failed");
exit(1);
}
터미널에서 실행하는 경우 자식의 출력과 쉘 프롬프트가 인터리브되지 않도록 부모에서 wait를 사용해야 합니다.
답변2
커널의 관점에서 생각해 보세요. 하위 프로세스를 설정하여 다양한 캐시를 파괴하는 것일 뿐이며 다음에 해당 하위 프로세스를 실행하면 새 캐시 콘텐츠 중 일부를 재사용할 수 있습니다. 동시에 상위 프로세스가 다른 CPU에 예약될 수 있습니다.
답변3
원칙적으로 두 프로세스가 병렬로 실행될 수 있지만 상위 프로세스는 이미 CPU에서 활성화되어 있으며 하위 프로세스는 exec
출력을 생성하기 전에 먼저 새 프로세스를 생성해야 합니다. 상위 프로세스는 하위 프로세스가 해당 프로세스를 대체하기 전에 완료될 가능성이 높습니다.