具有分叉和共享内存的斐波那契数列生成器

问题描述 投票:0回答:1

我正在为作业问题而苦苦挣扎。我被要求:

编写一个程序,其主例程从用户那里获取一个参数 n (n<40), i.e. passed to your program when it was invoked from the shell. Your program shall then create a shared memory and a child process. The shared memory shall have a size of BUF_SZ*sizeof(unsigned short), where BUF_SZ is defined as 5 using a macro, e.g. “#define BUF_SZ 5”.

子进程应该从父进程获取 n 的值(你实际上有多种选择)并创建一个长度为 n 且其元素类型为 unsigned short 的斐波那契数列。您可以在 (https://en.wikipedia.org/wiki/Fibonacci_number) 找到有关斐波那契数列的更多信息。

子进程应一次创建一个元素,并等待一个随机时间间隔( 0 <= time < 2 seconds) between generating elements of the sequence. As soon as an element is generated, the child places the element in the shared memory by organizing it as described in class.

父进程应立即在共享黄油上打印它收到的元素,而无需等待子进程退出。

#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 指针早一个时,子进程将元素输出到缓冲区。问题是父进程陷入了无限循环,它不会切换到子进程。我不确定如何进行。

c memory-management operating-system fork shared-memory
1个回答
0
投票

几个问题...

  1. 你只能在父级中获取一个数字。你需要一个外层
    while
    循环。
  2. 你最后一个
    shm_open
    使用
    NAME2
    而不是
    NAME3
    。这导致
    inptr
    outptr
    指向 same 存储单元。因此,它们相互“别名”,并且它们将始终具有相同的值。
  3. inptr
    outptr
    应该有
    volatile
    [如 dimich 所述].
  4. 你需要
    int main(int argc,char **argv)
  5. 父母在收到孩子的最终数字后将无限循环
  6. 虽然我没有在下面的代码中这样做,但是孩子可以再发送一个最终值,它是一个哨兵(告诉父母它结束了)。当父母看到哨兵时,它会跳出外层循环(然后做一个
    wait(NULL)
    来收割孩子)。
  7. 因为斐波那契数不能为 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

© www.soinside.com 2019 - 2024. All rights reserved.