我正在开发一个程序,该程序使用共享内存为给定的数字计算collatz猜想。父级将创建一个子进程,然后子级将计算推测,并使用共享内存将其提供给父级,以便父级可以将值打印出来。 如果子进程无法计算出完整的猜想,因为它没有足够的空间将其存储在共享内存结构中,那么父进程将创建一个新的子进程,以继续最后一个进程的停止。 我遇到一个问题,即父进程中显示共享内存中子级结果的打印语句被多次打印。
/*********************************
* Applies the Collatz conjecture
* to the given positive integer
* using shared memory.
*********************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <sys/stat.h>
#define MAX_SEQUENCE 30
typedef struct {
int size; // Number of values in this sequence
short partial; // Flag
long num[MAX_SEQUENCE];
} shared_data;
int main(int argc, char* argv[])
{
// Name of the shared memory segment
const char *name = "myMemorySeg";
// Shared memory file descriptor
int shm_fd;
// A pointer to the shared memory segment
shared_data* shared_memory;
// Handle input validation
if (argc != 2) {
fprintf(stderr, "Usage: %s num\n", argv[0]);
exit(1);
}
// Get number from argument
int n = atoi(argv[1]);
do {
int pid;
// Create a child process with shared memory space
pid = create_child(&name, &shm_fd, &shared_memory);
// Parent
if (pid > 0) {
wait(NULL);
// Print out collatz results
int i;
for (i = 0; i < shared_memory->size; i++)
printf("%d ", shared_memory->num[i]);
// If this was only part of the sequence
// Then start the next sequence at the collatz of the last sequence value
if (shared_memory->partial)
n = get_collatz(shared_memory->num[MAX_SEQUENCE - 1]);
}
// Child
else if (pid == 0) {
// Generate the collatz sequence and store the result in the shared memory
int i = 0;
shared_memory->num[i++] = n; // Store the initial number
while (n != 1 && i < MAX_SEQUENCE) {
n = get_collatz(n);
shared_memory->num[i++] = n; // Store the next number
}
// If we have filled the sequence array and n hasn't reached 1
// then this is only a partial sequence
shared_memory->partial = (i == MAX_SEQUENCE && n != 1) ? 1 : 0;
// What is the sequence size?
shared_memory->size = i;
// Kill the child process
exit(0);
}
// Remove the shared memory object
shm_unlink(name);
} while (shared_memory->partial); // While the last sequence was partial
printf("\n");
return 0;
}
/********************************
* create_child()
*
* Opens a shared memory space
* and creates a child process
* to share that space with the
* parent.
*
* Returns the process id if
* successful, otherwise exits
* the parent process.
********************************/
int create_child(char **name, int *shm_fd, shared_data** shared_memory) {
// Create a shared memory object
*shm_fd = shm_open(*name, O_CREAT|O_RDWR, 0666);
// Configure the size of the shared memory object
ftruncate(*shm_fd, sizeof(shared_data));
// Memory map the shared memory object
*shared_memory = (shared_data *) mmap(0, sizeof(shared_data), PROT_WRITE, MAP_SHARED, *shm_fd, 0);
// Create child process
int pid;
// Return -1 if error
if ((pid=fork()) == -1) {
perror("Failed to create child process");
exit(1); // Kill parent process
}
// Otherwise return the pid created by fork
return pid;
}
/********************************
* get_collatz()
*
* Returns the result of running
* the input n through the
* collatz conjecture function.
********************************/
int get_collatz(int n) {
return (!(n%2)) ? (n/2) : (3*n + 1);
}
这是控制台输出的样子:
有趣的是,如果我在父进程中添加一条带有新行的打印语句,然后再从共享内存中打印出子进程的结果,如下所示:
do {
int pid;
printf("\n");
// Create a child process with shared memory space
pid = create_child(&name, &shm_fd, &shared_memory);
// Parent
if (pid > 0) {
wait(NULL);
// Print out collatz results
int i;
for (i = 0; i < shared_memory->size; i++)
printf("%d ", shared_memory->num[i]);
// If this was only part of the sequence
// Then start the next sequence at the collatz of the last sequence value
if (shared_memory->partial)
n = get_collatz(shared_memory->num[MAX_SEQUENCE - 1]);
}
// Child
然后,打印语句将输出正确的次数。
另一个有趣的事实是,仅当我将换行符打印语句放置在create_child()调用之前,而我放置在new_print打印语句之后,该解决方案才有效。
我不希望这些行之间用换行符分隔,我希望它们全部打印在一行上。有什么想法导致这些额外的打印语句吗?
答案 0 :(得分:3)
您要么需要添加适当的刷新调用,要么需要更改标准输出以不进行缓冲。
该库正在尝试提高效率,直到有完整的行才真正写入终端。因此,它将部分行存储在缓冲区中。 fork
结束时,您将获得两个基本相同的进程,即它们各自具有相同的缓冲数据。如果它们两个都完成一行输出,则它们都会写入缓冲的数据。
您可能仍然有一个问题,所有各种输出混杂在一起。处理此问题的更常用方法是只由一个过程负责所有输出,而“工人”过程将其结果传达回“经理”过程,以便以理智,有序的方式进行打印。