在C中读取和写入结构到管道

Posted

技术标签:

【中文标题】在C中读取和写入结构到管道【英文标题】:Reading and writing a structure to a pipe in C 【发布时间】:2011-01-27 23:23:41 【问题描述】:

我正在尝试编写一个由字符数组、整数值和指向管道的指针组成的结构。该结构表示单链表中的一个节点。

//Define a linked-list node object
typedef struct node
    char word[128];
    int frequency;
    struct node *next;
 NODE;

该程序的目标是使用管道将一个节点从几个并发的子进程传递给父进程。我实现的管道结构似乎适用于常规字符数组,但如果我尝试传递整个节点对象,则无法正常工作。

    //for each file argument, create a child process
        for (i = 1; i < argc; i ++)
        
            pipe(p[i-1]);
            pid = fork();

            if (pid == 0)
            
                //child process
                close(p[i-1][0]);
                NODE *tmp;
                NODE *out = freqCheck(argv[i], tmp);
                write(p[i-1][1], out, sizeof(NODE));
                exit(0);
            
        
if (pid > 0)
                //parent process
                int j;
                for (j = 0; j < argc-1; j++)
                
                    close(p[j][1]);
                    NODE *tmp;
                    read(p[j][0], tmp, sizeof(NODE));

                    printf("%s\n", tmp->word);
                


            

当父进程尝试从管道中读取并解释结构的属性之一时,我只是返回空值。

我正在使用一个由 2 个元素整数数组组成的数组来跟踪每个子进程的管道。上面的 printf 语句每次返回 null 。

知道我做错了什么吗?

FrqCheck 方法的代码:

//Method for determining the most occuring word
NODE * freqCheck(char *file, NODE *max)

    int i; 
    FILE *f;
    char str[128];

    //Set up head and tail nodes
    NODE *head = NULL;
    NODE *tail = NULL;

    if ((f = fopen(file, "r")) == NULL)
        
            //sprintf(output, "%s could not be opened.", file);
        else
        
            //scan each word of the input file
            while(fscanf(f, "%s ", str) != EOF)
            
                //if the linked-list has no nodes, create one
                if (head == NULL)
                
                    NODE *n;
                    n = (NODE *)malloc(sizeof(NODE));
                    strcpy(n->word, str);
                    n->frequency = 1;
                    n->next = NULL;
                    head = n;
                    tail = n;

                else  //search the linked list for the found word.

                    NODE *current = head;
                    int found = 0;

                    while((current != NULL) && (found == 0))
                    
                        //if the word is found increment the frequency
                        if (strcmp(current->word, str) == 0)
                        
                            current->frequency ++;
                            found = 1;
                        else
                        
                            current = current->next;
                        
                    

                    //if the word is not found, create a node and add to the liked-list
                    if (found == 0)
                    
                        NODE *new;
                        new = (NODE *)malloc(sizeof(NODE));
                        strcpy(new->word, str);
                        new->frequency = 1;
                        new->next = NULL;
                        tail->next = new;
                        tail = new;
                    
                
            
            //traverse the linked-list and find the word with the maximum frequency
            NODE *tmp = head;
            max = tmp;

            while (tmp != NULL)
            
                if (tmp->frequency > max->frequency)
                
                    max = tmp;
                else
                
                    tmp = tmp->next;
                
            
            //sprintf(output, "%s %s %d", file, max->word, max->frequency);
        
    //printf("%s\n", max->word);
    return max;

【问题讨论】:

【参考方案1】:

您在哪里为 NODE 结构分配存储空间? freqCheck 是否分配存储空间?在父进程中,当您调用read() 然后调用printf 时,您传入了一个未初始化的NODE 指针,因此您当然会得到未定义的行为。

【讨论】:

是的,频率检查构造链表并为每个节点分配内存。该方法扫描文件中的单词,并确定哪个单词出现最多。它返回一个节点实例。 @user362685,不管你用freqCheck做什么,你在父进程中仍然有未定义的行为。您永远不会为NODE *tmp 分配存储空间,但您将其传递给read(),然后将其传递给printf 解决了,谢谢。只需要将其更改为 NODE *tmp = malloc(sizeof(NODE))。【参考方案2】:

使用缓冲读取来读取数据,直到读取整个结构,因为来自父级的代码可以在来自子级的代码之前执行,然后读取不存在的数据。

【讨论】:

我尝试在父代码中添加一个 wait() 调用,确保父代码在子代码完成后执行,但我得到相同的结果。【参考方案3】:

您需要考虑两件事: 1) 执行协调:

这就是锁、信号量、事件等的用途。他们强制执行指令(您的代码行)运行的顺序。正是出于这个原因,它们的一些版本在进程之间运行,就像为线程运行的版本一样。你需要一个信号量——当一个节点被完全传输时,写入器进程应该 post() sem,读取器进程应该在 sem 上等待(),然后再尝试读取下一个。

2) 内存: 进程不共享地址空间。因此,读取器和写入器进程拥有的堆是不同的内存块。管道工作正常,但它就像一个套接字——你有将对象序列化和反序列化为原始字节流的所有麻烦。考虑到您的结构有多小,您可以考虑的另一件事是共享内存。

要考虑的最后一件事:指向节点结构中“下一个”节点的指针需要在子进程中更新。同样,它将这些节点复制到它自己的地址空间中的位置,因此必须相应地更新“下一个”指针。

【讨论】:

以上是关于在C中读取和写入结构到管道的主要内容,如果未能解决你的问题,请参考以下文章

不能在 C 中的管道中写入两次

C管道写入/读取双打序列失败

C:线程之间的FIFO,写入和读取字符串

通过管道读取和写入数据

C - 创建/写入/读取命名管道

在多个进程写入时读取命名管道