유닉스-포크 모니터-자식-프로토리
-
19-08-2019 - |
문제
약간의 병렬 처리가 도움이되는 응용 프로그램이 있습니다. 토론의 목적으로 10 개의 텍스트 파일이있는 디렉토리가 있고 프로그램을 시작하고 싶다고 가정 해 봅시다. 프로그램을 시작하고 싶습니다. 각각 10 개의 프로세스를 포크하고 각각 파일 중 하나를 취하고 파일의 내용을 어퍼 케이싱합니다. 나는 부모 프로그램이 아이들이 기다리다 함수 또는 사용 고르다 기능.
내가하고 싶은 것은 부모 프로세스가 각 포크 프로세스의 진행 상황을 모니터링하고 프로세스가 실행될 때 진행률 표시 줄과 같은 것을 표시하는 것입니다.
내 질문.
포크 프로세스 가이 정보를 부모에게 다시 전달하기위한 합리적인 대안은 무엇입니까? 어떤 IPC 기술을 사용하는 것이 합리적입니까?
해결책
진행 상황 만 모니터링하려는 이러한 종류의 상황에서 가장 쉬운 대안은 공유 메모리를 사용하는 것입니다. 모든 프로세스는 공유 메모리 블록에서 진행 값 (예 : 정수)을 업데이트하고 마스터 프로세스는 정기적으로 블록을 읽습니다. 기본적 으로이 체계에서 잠금이 필요하지 않습니다. 또한 마스터가 원할 때마다 정보를 읽을 수 있기 때문에 "폴링"스타일 애플리케이션입니다. 따라서 진행 데이터를 처리하기 위해 이벤트 처리가 필요하지 않습니다.
다른 팁
필요한 유일한 진전이 "얼마나 많은 일자리가 완료 되었습니까?"라면 간단합니다.
while (jobs_running) {
pid = wait(&status);
for (i = 0; i < num_jobs; i++)
if (pid == jobs[i]) {
jobs_running--;
break;
}
printf("%i/%i\n", num_jobs - jobs_running, num_jobs);
}
할 것입니다. 진행중인 진행 상황을보고하기 위해 여기에 다른 제안 중 일부가 멍청한 구현이 있습니다.
파이프 :
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int child(int fd) {
int i;
struct timespec ts;
for (i = 0; i < 100; i++) {
write(fd, &i, sizeof(i));
ts.tv_sec = 0;
ts.tv_nsec = rand() % 512 * 1000000;
nanosleep(&ts, NULL);
}
write(fd, &i, sizeof(i));
exit(0);
}
int main() {
int fds[10][2];
int i, j, total, status[10] = {0};
for (i = 0; i < 10; i++) {
pipe(fds[i]);
if (!fork())
child(fds[i][1]);
}
for (total = 0; total < 1000; sleep(1)) {
for (i = 0; i < 10; i++) {
struct pollfd pfds = {fds[i][0], POLLIN};
for (poll(&pfds, 1, 0); pfds.revents & POLLIN; poll(&pfds, 1, 0)) {
read(fds[i][0], &status[i], sizeof(status[i]));
for (total = j = 0; j < 10; j++)
total += status[j];
}
}
printf("%i/1000\n", total);
}
return 0;
}
공유 메모리 :
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
int child(int *o, sem_t *sem) {
int i;
struct timespec ts;
for (i = 0; i < 100; i++) {
sem_wait(sem);
*o = i;
sem_post(sem);
ts.tv_sec = 0;
ts.tv_nsec = rand() % 512 * 1000000;
nanosleep(&ts, NULL);
}
sem_wait(sem);
*o = i;
sem_post(sem);
exit(0);
}
int main() {
int i, j, size, total;
void *page;
int *status;
sem_t *sems;
size = sysconf(_SC_PAGESIZE);
size = (10 * sizeof(*status) + 10 * sizeof(*sems) + size - 1) & size;
page = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
status = page;
sems = (void *)&status[10];
for (i = 0; i < 10; i++) {
status[i] = 0;
sem_init(&sems[i], 1, 1);
if (!fork())
child(&status[i], &sems[i]);
}
for (total = 0; total < 1000; sleep(1)) {
for (total = i = 0; i < 10; i++) {
sem_wait(&sems[i]);
total += status[i];
sem_post(&sems[i]);
}
printf("%i/1000\n", total);
}
return 0;
}
명확성을 위해 오류 처리 등.
몇 가지 옵션 (어떤 경우, 어떤 것이라도 당신에게 적합 할 것인지는 알지 못합니다. 많은 것은 당신이 실제로하고있는 일에 의존합니다.
- 신호
- FIFOS / 명명 된 파이프
- 어린이 또는 기타 통과 된 핸들의 성병
- 메시지 대기열 (적절한 경우)
당신이 원하는 모든 것이 진행 상황 업데이트 만 있으면, 가장 쉬운 방법은 아마도 익명 파이프를 사용하는 것입니다. 파이프 (2) 호출은 파이프의 각 끝마다 하나의 파일 설명자를 제공합니다. 포크 직전에 전화를 걸어 부모가 첫 번째 FD를 듣고 아이가 두 번째로 글을 쓰게하십시오. (파일 디스크립터와 이들이 포함 된 2 요소 배열이 모두 공유 메모리 자체가 아닌 프로세스간에 공유되기 때문에 작동하지만 복사 된 쓰기이므로 값을 덮어 쓰지 않으면 값을 공유하기 때문에 작동합니다.)
오늘 일찍 누군가 누군가가 항상 파이프를 사용한다고 말했습니다.이를 통해 아이들은 모든 것이 잘 진행되고 있다는 부모 과정에 알림을 보낼 수 있습니다. 이것은 괜찮은 해결책으로 보이며 오류를 인쇄하려는 장소에서 특히 유용하지만 더 이상 stdout/stderr 등에 액세스 할 수 없습니다.
boost.mpi 이 시나리오에서 유용해야합니다. 과잉을 고려할 수도 있지만 확실히 조사 할 가치가 있습니다.
www.boost.org/doc/html/mpi.html