현재 운영체제와 동시성을 연구하고 있습니다. 프로세스 스케줄러에 관한 제 실습 중 하나는 C 언어를 사용하여 Linux에서 여러 프로세스가 밀리 초 단위로 "병렬"로 작동하는 방식을 파악하는 것입니다.Linux에서 C의 fork()가 생성 한 하위 프로세스에서 쉘의 출력 리디렉션이 어떻게 작동합니까?
/* This file's name is Task05_3.c */
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
int kill(pid_t pid, int sig);
unsigned usleep(unsigned seconds);
#define NUMBER_OF_PROCESSES 7
#define MAX_EXPERIMENT_DURATION 4
long int getDifferenceInMilliSeconds(struct timeval start, struct timeval end)
{
int seconds = end.tv_sec - start.tv_sec;
int useconds = end.tv_usec - start.tv_usec;
int mtime = (seconds * 1000 + useconds/1000);
return mtime;
}
int main(int argc, char const *argv[])
{
struct timeval startTime, currentTime;
int diff;
int log[MAX_EXPERIMENT_DURATION + 2] = {-1};
/* initialization */
for (int k = 0; k < MAX_EXPERIMENT_DURATION + 2; ++k)
log[k] = -1;
gettimeofday(&startTime, NULL);
pid_t pid_for_diss = 0;
for (int i = 0; i < NUMBER_OF_PROCESSES; ++i)
{
pid_for_diss = fork();
if (pid_for_diss < 0) {
printf("fork error, errno(%d): %s\n", errno, strerror(errno));
} else if (pid_for_diss == 0) {
/* This loop is for logging when the child process is running */
while (1) {
gettimeofday(¤tTime, NULL);
diff = getDifferenceInMilliSeconds(startTime, currentTime);
if (diff > MAX_EXPERIMENT_DURATION)
{
break;
}
log[diff] = i;
}
// for (int k = 0; k < MAX_EXPERIMENT_DURATION + 2; ++k)
// {
// if (log[k] != -1)
// {
// printf("%d, %d\n", log[k], k);
// }
// }
// exit(0);
break;
}
}
/* This loop is for print the logged results out */
if (pid_for_diss == 0)
{
for (int k = 0; k < MAX_EXPERIMENT_DURATION + 2; ++k)
{
if (log[k] != -1)
{
printf("%d, %d\n", log[k], k);
}
}
kill(getpid(), SIGKILL);
}
int status;
while (wait(&status) != -1);// -1 means wait() failed
printf("Bye from the parent!\n");
}
기본적으로, 여기에 내 생각은 부모 프로세스가 포크 (7 개 자식 프로세스를 생성)과 경쟁하도록 강제 while 루프로 설정하는 내가 루프를 설정하는 것이 있습니다 : 여기 내 코드입니다 CPU 사용 시간. 그리고 자식 프로세스가 실행될 때마다, 부모 프로세스의 현재 시간과 시작 시간의 차이를 실행중인 자식 프로세스에 속한 어레이에 기록합니다. 그런 다음 7 개의 프로세스가 while 루프를 깰 때마다 각 하위 프로세스가 로그 된 결과를 인쇄하기위한 루프를 또 하나 설정합니다.
그러나 Linux 컴퓨터에서 .csv 파일로 출력을 리디렉션하려고하면 이상한 일이 발생했습니다. 먼저 내 for 루프에서 인쇄 할 루프를 설정합니다 (코드에서 볼 수 있듯이) , 나는 bash는 직접 ./Task05_3
를 실행하고 여기에 결과 :
[email protected]:osc$ gcc -std=c99 Task05_3.c -o Task05_3
[email protected]:osc$ ./Task05_3
5, 0
4, 0
6, 0
4, 1
1, 0
4, 2
4, 3
4, 4
0, 0
1, 1
6, 1
1, 2
1, 3
1, 4
5, 1
5, 2
5, 3
5, 4
6, 2
6, 3
2, 0
6, 4
2, 1
2, 2
2, 3
2, 4
0, 1
3, 0
0, 2
0, 3
0, 4
3, 1
3, 2
3, 3
3, 4
Bye from the parent!
[email protected]:osc$
당신은 (모두 부모 프로세스와 자식 프로세스에서) 모든 결과가 터미널에 인쇄하고 그 결과의되었음을 여기에서 볼 수 있습니다 자식 프로세스는 무작위 순서로 (이것은 표준 출력에 동시에 쓰는 여러 프로세스로 인해 발생할 수 있습니다). 그러나 ./Task05_3 > 5output_c.csv
에 의해 실행하려고하면 대상이되는 .csv 파일에 부모 프로세스의 결과 만 포함되어 있습니다. 다음과 같이 보입니다. Result_in_csv01
내 첫 번째 질문은 .csv 파일 만 상위 프로세스의 프롬프트가 포함되어 있습니까? 그것은 bash에서 입력 한 명령어가 부모 프로세스의 출력 만 리디렉션하고 자식 프로세스의 출력 스트림과는 아무런 관련이 없기 때문입니까?
주요 for 루프 내에 for 루프 (인쇄용)를 넣고 (위 코드의 for 루프를 참조하십시오) ./Task05_3 > 5output_c.csv
코드를 실행하면 더 혼란스러운 일이 발생합니다. 파일은 이제 다음과 같이 보입니다 : Result_in_csv02
이제 모든 결과가 포함됩니다! 그리고 자식 프로세스의 결과의 순서는 더 이상 임의가 아닙니다! (실행중인 하위 프로세스가 결과를 모두 인쇄 할 때까지 다른 자식 프로세스가 대기 상태 인 것은 분명합니다. 그래서 두 번째 질문은 단순히 for 루프의 위치를 변경 한 후에 이것이 일어날 수있는 방법이라는 것입니다.
추신.
[email protected]:osc$ cat /proc/version
Linux version 3.10.0-693.2.2.el7.x86_64 ([email protected]) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)) #1 SMP Tue Sep 12 22:26:13 UTC 2017
그리고 GCC 버전은 다음과 같습니다 : 표준 입출력 기능을 통해
[email protected]:osc$ gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
답장과 설명에 감사드립니다. 정말 분명하고 도움이됩니다. 그건 그렇고, 내 자식 프로세스의 출력이 줄 버퍼가있는 경우에 터미널에 무작위로 인쇄 되었기 때문에 파일로 리다이렉트 할 때 왜 내 자식 프로세스의 출력이 나타나는 지 궁금했다. 조금 더 구체적으로 설명해 주시겠습니까? Thx again ~ – TyBcodar
@TyBcodar 두 번째 버전에서는 각 자식에서 (exit (0) 호출의 일부로) 하나의 원자'write()'만 수행되기 때문에 단일 프로세스에 대한 모든 출력 즉시 함께 나타납니다. 첫 번째 버전에서는 모든 프로세스의 모든 라인이 독립적으로 즉시 작성됩니다. – melpomene