具有分叉和共享存储器的Fibonacci序列生成器

mm9b1k5b  于 2023-03-07  发布在  其他
关注(0)|答案(1)|浏览(106)

我在努力解决家庭作业的问题。我被要求:
编写一个程序,其主例程从用户处获得一个参数n(n〈40),即从 shell 调用时传递给您的程序。然后您的程序应创建一个共享内存和一个子进程。共享内存的大小应为BUF_SZ*sizeof(无符号短整型),其中BUF_SZ使用宏定义为5,例如“#define BUF_SZ 5”。
子进程应该从父进程获得n的值(实际上有多种选择),并创建一个长度为n且元素类型为unsigned short的斐波那契数列,您可以在(https://en.wikipedia.org/wiki/Fibonacci_number)中找到关于斐波那契数列的更多信息。
子进程将创建元素,一次一个,并在生成序列元素之间等待一个随机的时间间隔(0〈= time〈2秒)。一旦元素生成,子进程将按照类中描述的方式组织元素,将其放入共享内存中。
父进程应立即打印其在共享缓冲器上接收到的元素,而无需等待子进程退出。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
#include <sys/mman.h>
#include <errno.h>
#include <fcntl.h>

#define BUF_SZ 5
#define NAME "buffer"
#define NAME2 "inptr"
#define NAME3 "outptr"

int main() {
    int fd[2];
    int n = atoi(argv[1]);
    unsigned short *data;
    int* inptr;
    int* outptr;
    int size = BUF_SZ * sizeof(unsigned short);
    int size2 = sizeof(int);
    
    /*while(n >= 40 || n <= 0) {
        printf("Enter a positive integer less than 40: ");
        scanf("%i", &n);
    }*/
    
    int shmid = shm_open(NAME, O_CREAT|O_RDWR, 0666);
    ftruncate(shmid, size);
    data = (unsigned short*) mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, shmid, 0);
    
    int shmid2 = shm_open(NAME2, O_CREAT|O_RDWR, 0666);
    ftruncate(shmid2, size2);
    inptr = (int*) mmap(NULL, size2, PROT_READ|PROT_WRITE, MAP_SHARED, shmid2, 0);
    
    int shmid3 = shm_open(NAME2, O_CREAT|O_RDWR, 0666);
    ftruncate(shmid3, size2);
    outptr = (int*) mmap(NULL, size2, PROT_READ|PROT_WRITE, MAP_SHARED, shmid3, 0);
    
    memset(inptr, 0, size2); //in variable
    memset(outptr, 0, size2); //out variable
    
    pipe(fd);
    pid_t pid = fork();
    
    if(pid > 0) {                   
        write(fd[1], &n, sizeof(n)); //write n value to child   
        while (*inptr == *outptr);
        printf("%i\n", data[*outptr]);
        fflush(stdout);
        *outptr = (*outptr + 1) % BUF_SZ;           
    }
    else if(pid == 0) {
        read(fd[0], &n, sizeof(n)); //get n value from parent
        int prev = 0;
        int curr = 1;
        int tmp;
    
        for(int i = 0; i <= n; i++) {       
            while (((*inptr + 1) % BUF_SZ) == *outptr);
    
            if(i == 0) {
                data[*inptr] = 0;
                *inptr = (*inptr + 1) % BUF_SZ; 
            }
            else if(i == 1) {
                data[*inptr] = 1;
                *inptr = (*inptr + 1) % BUF_SZ; 
            }
        
            tmp = curr;
            curr += prev;
            prev = tmp;
            data[*inptr] = curr;
            *inptr = (*inptr + 1) % BUF_SZ;
        }
    }
    else {
        printf("failed");
    }
    
    return 0;

}

我为fib序列的元素以及in和out指针创建了共享内存缓冲区。In向缓冲区写入,out从缓冲区读取。父进程检查in和out指针是否相等。当它们不相等时,它从缓冲区中读取。2当入指针比出指针提前一个指针时,子进程输出元素到缓冲区。问题是父进程陷入了无限while循环,无法切换到子进程,我不知道该如何继续。

xfb7svmp

xfb7svmp1#

一些问题...
1.在父循环中只获取一个数字,需要一个外部的while循环。
1.最后一个shm_open使用NAME2而不是NAME3,这会导致inptroutptr指向同一个内存单元,因此,它们彼此"别名",并且它们将始终是相同的值。

  1. inptroutptr上面应该有volatile [正如dimich提到的]。
    1.您需要int main(int argc,char **argv)
    1.父节点将在从子节点接收到最终数字后 * 无限 * 循环。
    1.虽然我没有在下面的代码中这样做,但子循环可以再发送一个final值,即sentinel(告诉父循环到此为止),当父循环看到这个sentinel时,它就跳出外循环(然后执行wait(NULL)以获取子循环)。
    1.由于斐波那契数列不能为0,因此它是一个不错的标记值。
    下面是正确的代码。它是带注解的。我添加了一些调试打印来提供帮助:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/mman.h>

#define BUF_SZ 5
#define NAME "buffer"
#define NAME2 "inptr"
#define NAME3 "outptr"

#if DEBUG
#define dbgprt(_fmt...) \
    printf(_fmt)
#else
#define dbgprt(_fmt...) \
    do { } while (0)
#endif

int
main(int argc,char **argv)
{
    int fd[2];
    int n = atoi(argv[1]);
    unsigned short *data;
// NOTE/BUG: without volatile the optimizer could incorrectly elide code
#if 0
    int *inptr;
    int *outptr;
#else
    volatile int *inptr;
    volatile int *outptr;
#endif
    int size = BUF_SZ * sizeof(unsigned short);
    int size2 = sizeof(int);

    /* while(n >= 40 || n <= 0) { printf("Enter a positive integer less than 40: "); scanf("%i", &n); } */

    int shmid = shm_open(NAME, O_CREAT | O_RDWR, 0666);
    ftruncate(shmid, size);
    data = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, shmid, 0);

    int shmid2 = shm_open(NAME2, O_CREAT | O_RDWR, 0666);
    ftruncate(shmid2, size2);
    inptr = mmap(NULL, size2, PROT_READ | PROT_WRITE, MAP_SHARED, shmid2, 0);

// NOTE/BUG: this uses the same file as shmid2, so inptr are aliased together
#if 0
    int shmid3 = shm_open(NAME2, O_CREAT | O_RDWR, 0666);
#else
    int shmid3 = shm_open(NAME3, O_CREAT | O_RDWR, 0666);
#endif
    ftruncate(shmid3, size2);
    outptr = mmap(NULL, size2, PROT_READ | PROT_WRITE, MAP_SHARED, shmid3, 0);

#if 0
    memset((void *) inptr, 0, size2);           // in variable
    memset((void *) outptr, 0, size2);          // out variable
#else
    *inptr = 0;
    *outptr = 0;
#endif

    pipe(fd);
    pid_t pid = fork();

    if (pid > 0) {
        write(fd[1], &n, sizeof(n));    // write n value to child
// NOTE/FIX: we need an outer loop to get all numbers from the child
        while (1) {
            while (*inptr == *outptr);
            printf("parent: %i\n", data[*outptr]);
            fflush(stdout);
            *outptr = (*outptr + 1) % BUF_SZ;
            dbgprt("parent: inptr=%d outptr=%d\n",*inptr,*outptr);
        }
    }
    else if (pid == 0) {
        read(fd[0], &n, sizeof(n));     // get n value from parent
        int prev = 0;
        int curr = 1;
        int tmp;

        dbgprt("child: n=%d\n",n);

        for (int i = 0; i <= n; i++) {
            while (((*inptr + 1) % BUF_SZ) == *outptr);

            if (i == 0) {
                data[*inptr] = 0;
                dbgprt("child: i0\n");
                *inptr = (*inptr + 1) % BUF_SZ;
            }
            else if (i == 1) {
                dbgprt("child: i1\n");
                data[*inptr] = 1;
                *inptr = (*inptr + 1) % BUF_SZ;
            }

            tmp = curr;
            curr += prev;
            prev = tmp;
            printf("curr=%d\n",curr);
            data[*inptr] = curr;

            *inptr = (*inptr + 1) % BUF_SZ;
            dbgprt("child: inptr=%d outptr=%d\n",*inptr,*outptr);
        }
    }
    else {
        printf("failed");
    }

    return 0;

}

在上面的代码中,我使用了cpp条件来表示旧代码和新代码:

#if 0
// old code
#else
// new code
#endif

#if 1
// new code
#endif

注意:通过unifdef -k运行文件可以清除此问题

相关问题