我有一个应用程序,其中一些并行处理将是有益的。出于讨论的目的,假设有一个目录中包含10个文本文件,我想启动一个程序,该程序分离10个进程,每个进程获取一个文件,并高举文件内容。我确认父程序可以使用等待功能之一或使用选择功能等待孩子完成。
我想要做的是让父进程监视每个分叉进程的进度,并在进程运行时显示进度条。
我的问题。
我有什么合理的替代方案可以让分叉流程将这些信息传回给父母?什么IPC技术合理使用?
答案 0 :(得分:2)
在这种只想监视进度的情况下,最简单的方法是使用共享内存。每个进程在共享存储器块上更新它的进度值(例如,整数),并且主进程定期读取块。基本上,您不需要在此方案中进行任何锁定。此外,它是一个“轮询”样式应用程序,因为主服务器可以随时读取信息,因此您不需要任何事件处理来处理进度数据。
答案 1 :(得分:2)
如果您需要的唯一进展是“完成了多少工作?”,那么就简单
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;
}
为了清楚起见,错误处理等被忽略了。
答案 2 :(得分:1)
一些选项(不知道哪个适用于你 - 很大程度上取决于你实际在做什么,因为选择了“大写文件”类比):
答案 3 :(得分:1)
如果你想要的只是进度更新,到目前为止最简单的方法可能是使用匿名管道。 pipe(2)调用将为您提供两个文件描述符,一个用于管道的每一端。在fork之前调用它,让父级监听第一个fd,子级写入第二个fd。 (这是有效的,因为文件描述符和包含它们的双元素数组在进程之间共享 - 不是共享内存本身,但是它是写时复制的,因此它们共享值,除非你覆盖它们。)
答案 4 :(得分:0)
今天早些时候有人告诉我他们总是使用管道,孩子们可以通过管道向父流程发送通知,表明一切顺利。这似乎是一个不错的解决方案,在您想要打印错误但不再能访问stdout / stderr等的地方特别有用。
答案 5 :(得分:0)
Boost.MPI应该很有用。你可能认为它有点过分,但绝对值得研究:
www.boost.org/doc/html/mpi.html