簡體   English   中英

C程序多次詢問用戶輸入

[英]C program asking for user input multiple times

編寫一個演示共享內存的非常基本的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 ,然后在第四次求和迭代中,要求第二個輸入在計算總和之前先數次。

問題在於您要在外部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;
        }
    }
}

該代碼在忙等待循環中進行調試,每個讀取周期有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()等待子項退出。

注意:這里有一個問題,在極端情況下,父母退出,孩子仍在等待父母輸入值-如果用戶在shared_ints [3]!= 0時中斷程序會發生這種情況

為了展示@Jonathan Leffler的出色答案,這是我的修復建議:

    /* These are better declared outside the while loop */
    // 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;                                                            

// Fork the process                                                   
while(1) {                                                            

    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;   
        /* Child process should finish, so it doesn't fork
           and in the upper while loop. this is a fast way to do it */
        exit(0);                            
    }                                                                 
}

在大while循環的每次迭代中,父進程和子進程在此行中調用fork()

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

在每次迭代之后,您將反復產生更多的子進程,並且可能會創建意外的交互。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM