使用 fork() 和 pipe() 写入从 1 到 100 的数字
Write numbers from 1 to 100 using fork() and pipe()
我需要写一个有2个进程的程序,一个写偶数,另一个写奇数。结果,我必须按从 1 到 100 的顺序排列数字。
我输入了这段代码,但是当涉及到处理部分时,它卡在了 printProc()
函数中。我猜是管道读写的问题。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int fd[2];
int printProc(int startNumber, int procNumber);
int main()
{
pid_t childpid;
pipe(fd);
int start = 0;
write(fd[0], &start, sizeof(start));
if ((childpid = fork()) == -1)
{
perror("fork");
}
if (childpid == 0)
{
printf("run child\n");
printProc(1, 0);
}
else
{
printf("run parent\n");
printProc(2, 1);
}
return 0;
}
int printProc(int startNumber, int procNumber)
{
FILE *f;
f = fopen("output.txt", "a+");
int num = startNumber;
int proc;
while (num <= 100)
{
read(fd[1], &proc, sizeof(proc));
if (proc == procNumber)
{
fprintf(f, "%d", num);
num = num + 2;
proc = (proc + 1) % 2;
write(fd[0], &proc, sizeof(proc));
}
}
return 0;
}
您需要 2 个管道,当一个进程写入数字时,它会将一些数据写入一个管道,以便另一个进程知道它可以写入自己的数字等。
实现示例:
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
int main(void) {
int parent_to_child[2];
int child_to_parent[2];
if (pipe(parent_to_child) == -1 || pipe(child_to_parent) == -1) {
perror("pipe");
return EXIT_FAILURE;
}
pid_t cpid = fork();
if (cpid == -1) {
perror("fork");
return EXIT_FAILURE;
}
if (cpid == 0) {
close(parent_to_child[1]);
close(child_to_parent[0]);
int i = 1;
bool buf;
ssize_t ret;
while ((ret = read(parent_to_child[0], &buf, sizeof buf)) > 0) {
fprintf(stdout, "%d ", i);
fflush(stdout);
if (write(child_to_parent[1], &buf, sizeof buf) != sizeof buf) {
break;
}
i += 2;
}
close(parent_to_child[0]);
close(child_to_parent[1]);
} else {
close(parent_to_child[0]);
close(child_to_parent[1]);
int i = 2;
bool buf = true;
ssize_t ret;
while (i <= 100 &&
write(parent_to_child[1], &buf, sizeof buf) == sizeof buf &&
(ret = read(child_to_parent[0], &buf, sizeof buf)) > 0) {
fprintf(stdout, i != 100 ? "%d " : "%d\n", i);
fflush(stdout);
i += 2;
}
close(parent_to_child[1]);
close(child_to_parent[0]);
}
}
如果你想用管道同步2个进程,你真的应该使用一对管道,前者由proc1读取并由proc2写入,后者由proc2读取并由proc1写入。从那里,您将读写句柄传递给 printProc
,仅此而已。
但是您的代码中还有另一个问题:您在两个进程中都以缓冲模式(fopen
)打开了一个输出文件。所以每个进程都会有自己的缓冲区。两个缓冲区将单独提供,并且仅在关闭时写入文件,这不是您想要的:您必须在 fork 之前打开输出文件,并在非缓冲模式下使用它。
所以你的代码可以变成:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int printProc(int startNumber, FILE *f, int fdin, int fdout);
int main()
{
pid_t childpid;
int fd[4];
FILE *f;
pipe(fd);
pipe(fd + 2);
int start = 0;
write(fd[0], &start, sizeof(start));
f = fopen("output.txt", "w");
if (f == NULL) {
perror("Error opening file");
return 1;
}
setbuf(f, NULL); // use unbuffered mode for output.txt
if ((childpid = fork()) == -1)
{
perror("fork");
}
if (childpid == 0)
{
printf("run child\n");
printProc(1, f, fd[1], fd[2]);
}
else
{
printf("run parent\n");
printProc(2, f, fd[3], fd[0]);
}
fclose(f);
return 0;
}
int printProc(int num, FILE *f, int fdin, int fdout)
{
int proc;
while (num <= 100)
{
read(fdin, &proc, sizeof(proc));
fprintf(f, "%d\n", num);
num = num + 2;
write(fdout, &proc, sizeof(proc));
}
return 0;
}
我建议在这里使用互斥量。您的关键部分将包含三个操作:
- 检查是否轮到你写
- 如果以上为真,写入输出
- 如果您写入输出,则向其他进程发出信号表明轮到他了
这是实现该功能的代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <sys/mman.h>
int main() {
pthread_mutex_t *pmutex;
short * even;
pthread_mutexattr_t attrmutex;
pthread_mutexattr_init(&attrmutex);
pthread_mutexattr_setpshared(&attrmutex, PTHREAD_PROCESS_SHARED);
pmutex = mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
even = mmap(NULL, sizeof(short), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
pthread_mutex_init(pmutex, &attrmutex);
pthread_mutex_lock(pmutex);
*even = 0;
if(fork() == 0){
int a = 2;
while(a <= 100) {
pthread_mutex_lock(pmutex);
if(*even) {
printf("%d\n", a);
*even = 0;
a = a + 2;
}
pthread_mutex_unlock(pmutex);
}
return 0;
}else {
int a = 1;
printf("%d\n", a);
*even = 1;
pthread_mutex_unlock(pmutex);
a = a + 2;
while(a <= 99) {
pthread_mutex_lock(pmutex);
if(!*even) {
printf("%d\n", a);
*even = 1;
a = a + 2;
}
pthread_mutex_unlock(pmutex);
}
}
pthread_mutex_destroy(pmutex);
pthread_mutexattr_destroy(&attrmutex);
}
两个进程共享两个变量:pmutex
(用于同步)和even
(用于检查允许哪个进程打印)。
我需要写一个有2个进程的程序,一个写偶数,另一个写奇数。结果,我必须按从 1 到 100 的顺序排列数字。
我输入了这段代码,但是当涉及到处理部分时,它卡在了 printProc()
函数中。我猜是管道读写的问题。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int fd[2];
int printProc(int startNumber, int procNumber);
int main()
{
pid_t childpid;
pipe(fd);
int start = 0;
write(fd[0], &start, sizeof(start));
if ((childpid = fork()) == -1)
{
perror("fork");
}
if (childpid == 0)
{
printf("run child\n");
printProc(1, 0);
}
else
{
printf("run parent\n");
printProc(2, 1);
}
return 0;
}
int printProc(int startNumber, int procNumber)
{
FILE *f;
f = fopen("output.txt", "a+");
int num = startNumber;
int proc;
while (num <= 100)
{
read(fd[1], &proc, sizeof(proc));
if (proc == procNumber)
{
fprintf(f, "%d", num);
num = num + 2;
proc = (proc + 1) % 2;
write(fd[0], &proc, sizeof(proc));
}
}
return 0;
}
您需要 2 个管道,当一个进程写入数字时,它会将一些数据写入一个管道,以便另一个进程知道它可以写入自己的数字等。
实现示例:
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
int main(void) {
int parent_to_child[2];
int child_to_parent[2];
if (pipe(parent_to_child) == -1 || pipe(child_to_parent) == -1) {
perror("pipe");
return EXIT_FAILURE;
}
pid_t cpid = fork();
if (cpid == -1) {
perror("fork");
return EXIT_FAILURE;
}
if (cpid == 0) {
close(parent_to_child[1]);
close(child_to_parent[0]);
int i = 1;
bool buf;
ssize_t ret;
while ((ret = read(parent_to_child[0], &buf, sizeof buf)) > 0) {
fprintf(stdout, "%d ", i);
fflush(stdout);
if (write(child_to_parent[1], &buf, sizeof buf) != sizeof buf) {
break;
}
i += 2;
}
close(parent_to_child[0]);
close(child_to_parent[1]);
} else {
close(parent_to_child[0]);
close(child_to_parent[1]);
int i = 2;
bool buf = true;
ssize_t ret;
while (i <= 100 &&
write(parent_to_child[1], &buf, sizeof buf) == sizeof buf &&
(ret = read(child_to_parent[0], &buf, sizeof buf)) > 0) {
fprintf(stdout, i != 100 ? "%d " : "%d\n", i);
fflush(stdout);
i += 2;
}
close(parent_to_child[1]);
close(child_to_parent[0]);
}
}
如果你想用管道同步2个进程,你真的应该使用一对管道,前者由proc1读取并由proc2写入,后者由proc2读取并由proc1写入。从那里,您将读写句柄传递给 printProc
,仅此而已。
但是您的代码中还有另一个问题:您在两个进程中都以缓冲模式(fopen
)打开了一个输出文件。所以每个进程都会有自己的缓冲区。两个缓冲区将单独提供,并且仅在关闭时写入文件,这不是您想要的:您必须在 fork 之前打开输出文件,并在非缓冲模式下使用它。
所以你的代码可以变成:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int printProc(int startNumber, FILE *f, int fdin, int fdout);
int main()
{
pid_t childpid;
int fd[4];
FILE *f;
pipe(fd);
pipe(fd + 2);
int start = 0;
write(fd[0], &start, sizeof(start));
f = fopen("output.txt", "w");
if (f == NULL) {
perror("Error opening file");
return 1;
}
setbuf(f, NULL); // use unbuffered mode for output.txt
if ((childpid = fork()) == -1)
{
perror("fork");
}
if (childpid == 0)
{
printf("run child\n");
printProc(1, f, fd[1], fd[2]);
}
else
{
printf("run parent\n");
printProc(2, f, fd[3], fd[0]);
}
fclose(f);
return 0;
}
int printProc(int num, FILE *f, int fdin, int fdout)
{
int proc;
while (num <= 100)
{
read(fdin, &proc, sizeof(proc));
fprintf(f, "%d\n", num);
num = num + 2;
write(fdout, &proc, sizeof(proc));
}
return 0;
}
我建议在这里使用互斥量。您的关键部分将包含三个操作:
- 检查是否轮到你写
- 如果以上为真,写入输出
- 如果您写入输出,则向其他进程发出信号表明轮到他了
这是实现该功能的代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <sys/mman.h>
int main() {
pthread_mutex_t *pmutex;
short * even;
pthread_mutexattr_t attrmutex;
pthread_mutexattr_init(&attrmutex);
pthread_mutexattr_setpshared(&attrmutex, PTHREAD_PROCESS_SHARED);
pmutex = mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
even = mmap(NULL, sizeof(short), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
pthread_mutex_init(pmutex, &attrmutex);
pthread_mutex_lock(pmutex);
*even = 0;
if(fork() == 0){
int a = 2;
while(a <= 100) {
pthread_mutex_lock(pmutex);
if(*even) {
printf("%d\n", a);
*even = 0;
a = a + 2;
}
pthread_mutex_unlock(pmutex);
}
return 0;
}else {
int a = 1;
printf("%d\n", a);
*even = 1;
pthread_mutex_unlock(pmutex);
a = a + 2;
while(a <= 99) {
pthread_mutex_lock(pmutex);
if(!*even) {
printf("%d\n", a);
*even = 1;
a = a + 2;
}
pthread_mutex_unlock(pmutex);
}
}
pthread_mutex_destroy(pmutex);
pthread_mutexattr_destroy(&attrmutex);
}
两个进程共享两个变量:pmutex
(用于同步)和even
(用于检查允许哪个进程打印)。