C:共享内存和分叉,打印语句执行多次

C:共享内存和分叉,打印语句执行多次,c,C,我正在开发一个程序,使用共享内存计算给定数字的collatz猜想。父进程将创建一个子进程,然后子进程将计算该猜想,并使用共享内存将其提供给父进程,以便父进程可以打印出该值。 如果子进程无法计算完整的推测,因为它在共享内存结构中的存储空间不足,那么父进程将创建一个新的子进程,在最后一个停止的位置继续。 我遇到一个问题,父进程中显示共享内存中孩子结果的print语句被多次打印 /********************************* * Applies the Collatz conj

我正在开发一个程序,使用共享内存计算给定数字的collatz猜想。父进程将创建一个子进程,然后子进程将计算该猜想,并使用共享内存将其提供给父进程,以便父进程可以打印出该值。 如果子进程无法计算完整的推测,因为它在共享内存结构中的存储空间不足,那么父进程将创建一个新的子进程,在最后一个停止的位置继续。 我遇到一个问题,父进程中显示共享内存中孩子结果的print语句被多次打印

/*********************************
 * 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);
}
/*********************************
*应用Collatz猜想
*到给定的正整数
*使用共享内存。
*********************************/
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义最大\u序列30
类型定义结构{
int size;//此序列中的值数
短部分;//标志
long num[MAX_序列];
}共享数据;
int main(int argc,char*argv[])
{
//共享内存段的名称
const char*name=“myMemorySeg”;
//共享内存文件描述符
int shm_fd;
//指向共享内存段的指针
共享数据*共享内存;
//处理输入验证
如果(argc!=2){
fprintf(stderr,“用法:%s num\n”,argv[0]);
出口(1);
}
//从参数中获取数字
int n=atoi(argv[1]);
做{
int-pid;
//创建具有共享内存空间的子进程
pid=创建子对象(&name,&shm\u fd,&shared\u内存);
//母公司
如果(pid>0){
等待(空);
//打印collatz结果
int i;
对于(i=0;isize;i++)
printf(“%d”,共享内存->num[i]);
//如果这只是序列的一部分
//然后在最后一个序列值的collatz处开始下一个序列
如果(共享内存->部分)
n=get_collatz(共享内存->num[MAX_SEQUENCE-1]);
}
//孩子
否则如果(pid==0){
//生成collatz序列并将结果存储在共享内存中
int i=0;
共享内存->num[i++]=n;//存储初始编号
而(n!=1&&inum[i++]=n;//存储下一个数字
}
//如果我们已经填充了序列数组,而n还没有达到1
//那么这只是一个部分序列
共享内存->部分=(i==MAX\u SEQUENCE&&n!=1)?1:0;
//序列大小是多少?
共享内存->大小=i;
//终止子进程
出口(0);
}
//删除共享内存对象
shm_取消链接(名称);
}while(shared_memory->partial);//当最后一个序列是partial时
printf(“\n”);
返回0;
}
/********************************
*创建子对象()
*
*打开共享内存空间
*并创建一个子进程
*与客户共享该空间
*家长。
*
*如果需要,返回进程id
*成功,否则退出
*父进程。
********************************/
int创建子对象(字符**名称,int*shm\u fd,共享数据**共享内存){
//创建共享内存对象
*shm_fd=shm_open(*名称,O_创建| O_RDWR,0666);
//配置共享内存对象的大小
ftruncate(*shm_fd,sizeof(共享数据));
//内存映射共享内存对象
*共享内存=(共享数据*)mmap(0,sizeof(共享数据),PROT_WRITE,MAP_shared,*shm_fd,0);
//创建子进程
int-pid;
//如果出现错误,则返回-1
如果((pid=fork())=-1){
perror(“未能创建子进程”);
退出(1);//终止父进程
}
//否则,返回由fork创建的pid
返回pid;
}
/********************************
*格特·科拉兹()
*
*返回运行的结果
*输入n通过
*collatz猜想函数。
********************************/
int get_collatz(int n){
返回(!(n%2))?(n/2):(3*n+1);
}
这是控制台输出的外观:

有趣的是,如果我在从共享内存打印子进程的结果之前,向父进程添加一个带有新行的print语句,如下所示:

    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
do{
int-pid;
printf(“\n”);
//创建具有共享内存空间的子进程
pid=创建子对象(&name,&shm\u fd,&shared\u内存);
//母公司
如果(pid>0){
等待(空);
//打印collatz结果
int i;
对于(i=0;isize;i++)
printf(“%d”,共享内存->num[i]);
//如果这只是序列的一部分
//然后在最后一个序列值的collatz处开始下一个序列
如果(共享内存->部分)
n=get_collatz(共享内存->num[MAX_SEQUENCE-1]);
}
//孩子
然后,打印语句将被输出正确的次数

另一个有趣的事实是,只有将换行打印语句放在create_child()调用之前,此解决方案才有效,而不是放在create_child()调用之后


我不希望这些语句被新行分隔,我希望它们都打印在一行上。知道是什么导致了这些额外的打印语句吗?

您需要添加适当的刷新调用,或者需要更改标准输出,使其不被缓冲

库正在努力提高效率,直到有一个完整的行时才真正写入终端。因此,它将部分行存储在缓冲区中。当您使用
fork
时,您将得到两个基本相同的进程,即,