C程序多次要求用户输入

时间:2015-07-07 21:24:58

标签: c shared-memory

编写一个演示共享内存的非常基本的C程序。程序需要继续计算两个输入的总和,直到用户执行^C(此处未显示)。

到目前为止,我的父母捕获用户输入,然后告诉孩子计算总和,然后父母打印总和(如作业所示)。

附上我的代码。

// Fork the process                                                   
while(1) {                                                            
    // Declare a shared memory integer array                          
    int *shared_ints = mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);                                                                        
    int x;                                                            
    int y;                                                            
    shared_ints[3] = 0;                                               

    if((pid = fork()) < 0) {                                          
        printf("Fork error \n");                                      
        exit(-1);                                                     
    } else if(pid > 0 && shared_ints[3] == 0) { // Parent code        
        // Ask user for first input                                   
        printf("Enter your first number:");                           
        scanf("%d", &x);                                              
        printf("\n");                                                 

        // Ask user for second input                                  
        printf("Enter your second number:");                          
        scanf("%d", &y);                                              
        printf("\n");                                                 

        // Assign first value to shared memory                        
        shared_ints[0] = x;                                           

        // Assign second value to shared memory                       
        shared_ints[1] = y;                                           

        // Tell child that it can compute the sum now                 
        shared_ints[3] = 1;                                           

        // Trap parent in a while-loop while the child                
        // computes the sum                                           
        while(shared_ints[3] == 1);                                   

        // Child has completed calculating the sum and                
        // the parent can print the sum                               
        if(shared_ints[3] == 2) {                                     
            printf("The sum is: %d", shared_ints[2]);                 
            printf("\n");                                             
        }                                                             
    } else { // Child code                                            
        // Wait for parent to accept input values                     
        while(shared_ints[3] == 0);                                   

        // Calculate the sum                                          
        shared_ints[2] = shared_ints[0] + shared_ints[1];             

        // Tell parent sum has been calculated                        
        shared_ints[3] = 2;                                           
    }                                                                 
}

总和计算有效,直到我进行总和计算的第四次迭代(这是输出):

Created shared memory object /my_shared_memory
Shared memory segment allocated correctly (16 bytes).
Enter your first number:1
Enter your second number:2
The sum is: 3
Enter your first number:Enter your first number:3
Enter your second number:4
The sum is: 7
Enter your first number:Enter your first number:5
Enter your second number:6
The sum is: 11
Enter your first number:Enter your first number:7
Enter your second number:8
Enter your second number:9
Enter your second number:

我看到的一个有趣的错误是,在打印总和后,程序会按照此处的建议请求第一次输入两次:Enter your first number:Enter your first number:3,然后在第四次求和迭代中,它会多次请求第二个数字在计算总和之前。

3 个答案:

答案 0 :(得分:3)

麻烦的是你在外while循环的每次迭代中都要分叉,所以第一次,你有一个孩子,然后你有一个孩子,认为它已经长大了,是父母(以及知道它的父母是父母)。随着你的继续,它会变得更糟。

另一个问题是您在外部while循环的每次迭代中分配共享内存。我不确定它确实是内存泄漏,但它可能不是一个好主意。

修复:

  • mmap()fork()移到while (1)循环之外。
  • 父进程将有一个循环 - 在它自己的函数中,而不是全部在main()内,请 - 从用户读取,传输给子,从子进程读取结果,然后继续。
  • 子进程将有一个循环 - 也在它自己的函数中 - 从父进程读取,计算并继续。
  • 确保孩子知道在父退出时如何退出。
  • 理想情况下,使用忙等待之外的同步机制。一些互斥量或几个信号量都会很好。这些过程会等待被告知他们要做的工作,而不是在等待下一个任务时旋转他们的车轮(非常快)。

或多或少的工作代码

这使用了标头"stderr.h"以及我编写的代码中的err_setarg0()err_syserr()函数,因为错误报告至关重要,这使得它变得简单。你应该可以通过该标题的工作版本和那些函数找到我的SO代码。

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "stderr.h"

static void be_childish(int *shared_ints);
static void be_parental(int *shared_ints);

int main(int argc, char **argv)
{
    const char *file = "fidget";
    int shared_seg_size = 4 * sizeof(int);

    err_setarg0(argv[0]);
    if (argc > 1)
        file = argv[1];

    int fd = open(file, O_RDWR|O_CREAT, 0600);
    if (fd < 0)
        err_syserr("Failed to open file %s for read/write\n", file);
    /* Assume sizeof(int) == 4 */
    if (write(fd, "abcdefghijklmnop", shared_seg_size) != shared_seg_size)
        err_syserr("Failed to write %d bytes to %s\n", shared_seg_size, file);
    int *shared_ints = mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (shared_ints == 0)
        err_syserr("Failed to mmap file %s\n", file);

    shared_ints[3] = 0;

    int pid;
    if ((pid = fork()) == -1)
        err_syserr("Failed to fork\n");
    else if (pid  == 0)
        be_childish(shared_ints);
    else
        be_parental(shared_ints);
    return 0;
}

static void be_childish(int *shared_ints)
{
    while (1)
    {
        // Wait for parent to generate input values
        while (shared_ints[3] == 0 || shared_ints[3] == 2)
        {
            printf("Child: %d\n", shared_ints[3]);
            usleep(500000);
        }

        if (shared_ints[3] != 1)
        {
            printf("Child: exiting\n");
            return;
        }

        // Calculate the sum
        shared_ints[2] = shared_ints[0] + shared_ints[1];

        printf("Child: calculated %d + %d = %d\n", shared_ints[0], shared_ints[1], shared_ints[2]);

        // Tell parent sum has been calculated
        shared_ints[3] = 2;
    }
}

static void be_parental(int *shared_ints)
{
    while (1)
    {
        int x;
        int y;
        // Ask user for first input
        printf("Enter your first number:");
        if (scanf("%d", &x) != 1)
        {
            printf("Parent: exiting\n");
            shared_ints[3] = -1;    /* Tell child to exit */
            return;
        }
        printf("\n");

        // Ask user for second input
        printf("Enter your second number:");
        if (scanf("%d", &y) != 1)
        {
            printf("Parent: exiting\n");
            shared_ints[3] = -1;    /* Tell child to exit */
            return;
        }
        printf("\n");

        // Assign first value to shared memory
        shared_ints[0] = x;

        // Assign second value to shared memory
        shared_ints[1] = y;

        // Tell child that it can compute the sum now
        shared_ints[3] = 1;

        // Trap parent in a while-loop while the child
        // computes the sum
        while (shared_ints[3] == 1)
        {
            printf("Parent: %d\n", shared_ints[3]);
            usleep(500000);
        }

        // Child has completed calculating the sum and
        // the parent can print the sum
        if (shared_ints[3] == 2)
        {
            printf("The sum is: %d", shared_ints[2]);
            printf("\n");
        }
        else
        {
            printf("Parent: unexpected control %d - exiting\n", shared_ints[2]);
            shared_ints[3] = -1;    /* Tell child to exit */
            return;
        }
    }
}

此代码在busy-wait循环中进行调试,每个读取周期延迟0.5秒。您可以调整一下以适合自己,并在确定它为您工作后输掉输出。请注意,除非您指定要创建/销毁的备用名称,否则代码会销毁文件fidget。它不会在文件退出时删除它;它可能应该。

样品运行

$ ./dualproc
Enter your first number:Child: 0
1

Enter your second number:Child: 0
2

Parent: 1
Child: calculated 1 + 2 = 3
Child: 2
The sum is: 3
Enter your first number:Child: 2
Child: 2
3

Enter your second number:Child: 2
4

Parent: 1
Child: calculated 3 + 4 = 7
Child: 2
The sum is: 7
Enter your first number:Child: 2
q
Parent: exiting
$ Child: exiting

$ 

父母在孩子出生前退出;那里没什么大惊喜。如果您愿意,可以升级代码以使用wait()等待孩子退出。

答案 1 :(得分:1)

注意:在父案件退出且孩子仍在等待父母输入值的极端情况下出现问题 - 如果用户在shared_ints [3]!= 0

时中断了程序,则会发生这种情况

为了展示@Jonathan Leffler的优秀答案,我的建议是:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="myApp">
  <div ng-controller='MyController'>
    <div ng-repeat="people in peoples">
      {{people.name}}
      <button ng-click="addOne(people)" class="button">Try it again</button>
      {{people.likes}}

    </div>
  </div>

答案 2 :(得分:0)

在big while循环的每次迭代中,父进程和子进程在此行中调用fork()

if((pid = fork()) < 0) {                                          

每次迭代后,您都会反复生成更多子进程,并且可能会创建意外的交互。