0

我正在使用叉子和管道来查找文件内部字符串中 1 和 0 的数量。但是,我从来没有达到我的程序的正确结束,它计算了 1 和 0。这是一个非常少量的代码,所以这里是整个程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>

int main (int argc, char** argv)
{
        int leftR, rightR;
        char *string;
        long size;
        int recursion = 0;
        if (argc == 3)
        {
                string = argv[1];
                size = strlen(string);
                printf("the string is %s\n", string);
                if (size <= 2)
                {

                        int bitCounter[2];
                        bitCounter[0] = 0;
                        bitCounter[1] = 0;
                        int i;
                        for (i=0; i < size; i++)
                        {
                                if (string[i]=='0')
                                {
                                        bitCounter[0]++;
                                }
                                else
                                {
                                        bitCounter[1]++;
                                }
                        }
                        write(STDOUT_FILENO, &bitCounter, sizeof(int)*2);
                        printf("read bits, sending back %d ones and %d zeroes\n", bitCounter[1], bitCounter[0]);
                        return 0;
                }
                else
                {
                        recursion = 1;
                }
        }
        if (argc == 2 || recursion)
        {
                char *data;
                if (!recursion)
                {
                        FILE* filePointer;
                        if ((filePointer = fopen(argv[1], "r")) == NULL)
                        {
                                perror("file didn't work");
                        }
                        fseek(filePointer, 0, SEEK_END);
                        size = ftell(filePointer);
                        fseek(filePointer, 0, SEEK_SET);
                    data = malloc(size+1);
                        fread(data, size, 1, filePointer);
                        fclose(filePointer);
                }
                else
                {
                        data = malloc(size+1);
                        data = string;
                }

                char *right;
                char *left = malloc((size/2)+1);
                if (size%2 == 0)
                {
                        right = malloc(size/2 + 1);
                }
                else
                {
                        right = malloc(size/2 + 2);
                }

                memcpy(left, data, size/2);

                if (size%2 == 0)
                {
                        memcpy(right, (size/2) + data, size/2);
                }
                else
                {
                        memcpy(right, (size/2) + data, (size/2) + 1);
                }

                int pidLeft, pidRight;
                int leftPipe[2];
                int rightPipe[2];

                pipe(leftPipe);
                pipe(rightPipe);

                fd_set readF;

                FD_ZERO(&readF);
                FD_SET(leftPipe[0], &readF);
                FD_SET(rightPipe[0], &readF);

                pidLeft = fork();
                if (pidLeft > 0)
                {
                        pidRight = fork();
                        if (pidRight > 0)
                        {
                                struct timeval timer;
                                timer.tv_sec = 3;
                                timer.tv_usec = 0;

                                close(rightPipe[1]);
                                close(leftPipe[1]);
                                dup2(leftPipe[0], STDOUT_FILENO);
                                dup2(rightPipe[0], STDOUT_FILENO);

                                select(2, &readF, NULL, NULL, &timer);
                                read(leftPipe[0], &leftR, sizeof(int)*2);
                                read(rightPipe[0], &rightR, sizeof(int)*2);
                                printf("going back to parent.\n");
                        }
                        else if (pidRight == 0)
                        {
                                close(rightPipe[0]);
                                execl("my_program", "my_program", right, "y",  NULL);
                                printf("recursion start\n");
                                exit(1);
                        }
                }
                else if (pidLeft == 0)
                {
                        close(leftPipe[0]);
                        execl("my_program", "my_program", left, "y", NULL);
                        printf("start recursion LEFT\n");
                        exit(1);
                }
                else
                {
                        fprintf(stderr, "something went wrong! No fork!\n");
                }
        }
        else
        {
                fprintf(stderr, "Please input file name properly\n");
                exit(1);
        }
    int zeroes = leftR + rightR;
    int* numOnes[2];
    numOnes[0] = &leftR + sizeof(int);
    numOnes[1] = &rightR + sizeof(int);
    int ones = (int) *numOnes[0] + (int) *numOnes[1];
    printf("0's: %d\n1's: %d\n", zeroes, ones);
    return 0;

}

但是,输出永远不会达到我想要的结果,它将所有内容加起来:

the string is 01010▒z
the string is 010
the string is 0
read bits, sending back 0 ones and 1 zeroes
the string is 10▒z
the string is 10
read bits, sending back 1 ones and 1 zeroes
the string is ▒z
read bits, sending back 2 ones and 0 zeroes
the string is 10
read bits, sending back 1 ones and 1 zeroes
the string is 10100
z
the string is 101
the string is 1
read bits, sending back 1 ones and 0 zeroes
the string is 01
read bits, sending back 1 ones and 1 zeroes
the string is 00
z
the string is 00
read bits, sending back 0 ones and 2 zeroes
the string is
z
read bits, sending back 2 ones and 0 zeroes
(140) Admin $

几个要点可以更容易地理解代码:

  • argc 在子进程中执行时只有 3
  • 如果字符串小于或等于 2,children 只会读取字符串,否则再次递归地将字符串切成两半(并生成更多孩子)
  • 父母生一个左右孩子,都拿一半的弦来工作

我想几个简单的问题开始将是:

  • 我是否正确使用了 select() 和 execl() ?
  • 我是否正确使用了 read() 和 write()?
  • 我缺少的主要流程中是否有出口?
  • 孩子们都在正确地工作和使用管道吗?
  • (不太重要)字符串中的奇怪字符是否会弄乱我的计数?那是我的字符串中的一个空终止符吗?
4

1 回答 1

1

这是最难破解的坚果之一。该代码正在做一项晦涩的工作,并且编写得相当晦涩。据我所知,它应该被调用my_program,并且应该使用文件名作为单个参数来调用。然后该进程将打开文件,将其内容读入两个数组(leftright),而无需确保它们是字符串(无空终止)。然后该过程分叉两次。然后一个人用left(非)字符串作为参数和它的信息来执行自己left,一个人用right(非)字符串作为参数和它是正确的信息来执行自己。父进程搞砸了select()没有很好的理由,也没有检查返回值。然后它调用 read 以获取有关两个管道的信息。这些读取会阻塞,直到有数据准备好,所以这select()真的没有帮助。(我仍在尝试找出递归位适合的位置。)此外,大多数系统调用都没有进行错误检查。

但是,考虑到大纲操作(读取文件、拆分、子执行并各做一半并报告回来),我将编写如下内容:

#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static void err_exit(char const *fmt, ...);

int main(int argc, char * *argv)
{
    int l_data[2]  = { -1, -1 };
    int r_data[2] = { -1, -1 };
    char *string;
    size_t size;
    char *arg0 = argv[0];

    if (argc != 2 && argc != 3)
        err_exit("Usage: %s file\n", argv[0]);

    if (argc == 3)
    {
        /* Child process */
        string = argv[1];
        size = strlen(string);
        fprintf(stderr, "%d: the string is %s\n", (int)getpid(), string);
        if (size <= 2)
        {
            int bitCounter[2];
            bitCounter[0] = 0;
            bitCounter[1] = 0;
            for (size_t i = 0; i < size; i++)
            {
                if (string[i] == '0')
                    bitCounter[0]++;
                else if (string[i] == '1')
                    bitCounter[1]++;
            }
            if (write(STDOUT_FILENO, bitCounter, sizeof(int)*2) != sizeof(int)*2)
                err_exit("%d: failed to write on standard output\n",
                        (int)getpid());
            fprintf(stderr, "%d: read bits, sending back %d ones and %d zeroes\n",
                   (int)getpid(), bitCounter[1], bitCounter[0]);
            exit(0);
        }
        fprintf(stderr, "%d: doing recursion - string too big (%zu)\n",
                (int)getpid(), size);
    }

    char *data = string;
    if (argc == 2)
    {
        FILE *filePointer;
        if ((filePointer = fopen(argv[1], "r")) == NULL)
        {
            perror("file didn't work");
            exit(1);
        }
        fseek(filePointer, 0, SEEK_END);
        size = ftell(filePointer);
        fseek(filePointer, 0, SEEK_SET);
        data = malloc(size+1);
        fread(data, size, 1, filePointer);
        data[size] = '\0';
        if (data[size-1] == '\n')
            data[--size] = '\0';
        fclose(filePointer);
        fprintf(stderr, "%d: data <<%s>>\n", (int)getpid(), data);
    }

    size_t l_size = size/2;
    size_t r_size = size - l_size;
    char *left = malloc(l_size+1);
    char *right = malloc(r_size+1);

    memcpy(left, data, l_size);
    left[l_size] = '\0';
    memcpy(right, data + l_size, r_size);
    right[r_size] = '\0';

    int l_pid, r_pid;
    int l_pipe[2] = { -1, -1 };
    int r_pipe[2] = { -1, -1 };

    if (pipe(l_pipe) != 0 || pipe(r_pipe) != 0)
        err_exit("%d: Failed to create pipes\n", (int)getpid());

    fprintf(stderr, "%d: forking (l_size = %zu, r_size = %zu)\n",
            (int)getpid(), l_size, r_size);
    l_pid = fork();
    if (l_pid < 0)
        err_exit("%d: Failed to fork() left child\n", (int)getpid());
    else if (l_pid == 0)
    {
        dup2(l_pipe[1], STDOUT_FILENO);
        close(l_pipe[0]);
        close(l_pipe[1]);
        close(r_pipe[0]);
        close(r_pipe[1]);
        fprintf(stderr, "%d: left execing with string <<%s>>\n", (int)getpid(), left);
        execl(arg0, arg0, left, "y", NULL);
        err_exit("%d: failed to start recursion LEFT\n", (int)getpid());
    }
    else if ((r_pid = fork()) < 0)
        err_exit("%d: Failed to fork() right child\n", (int)getpid());
    else if (r_pid == 0)
    {
        dup2(r_pipe[1], STDOUT_FILENO);
        close(l_pipe[0]);
        close(l_pipe[1]);
        close(r_pipe[0]);
        close(r_pipe[1]);
        fprintf(stderr, "%d: right execing with string <<%s>>\n", (int)getpid(), right);
        execl(arg0, arg0, right, "y",  NULL);
        err_exit("%d: failed to start recursion RIGHT\n", (int)getpid());
    }
    else
    {
        /* Parent process */
        int nbytes;
        close(r_pipe[1]);
        close(l_pipe[1]);
        if ((nbytes = read(l_pipe[0], l_data, sizeof(int)*2)) != sizeof(int)*2)
            err_exit("%d: Read left pipe failed (%d)\n", (int)getpid(), nbytes);
        if ((nbytes = read(r_pipe[0], r_data, sizeof(int)*2)) != sizeof(int)*2)
            err_exit("%d: Read right pipe failed (%d)\n", (int)getpid(), nbytes);
        close(l_pipe[0]);
        close(r_pipe[0]);
    }

    int zeroes = l_data[0] + r_data[0];
    int ones   = l_data[1] + r_data[1];
    if (argc == 3)
    {
        int data[2] = { zeroes, ones };
        if (write(STDOUT_FILENO, data, sizeof(data)) != sizeof(data))
            err_exit("%d: failed to read binary data from stdin\n", (int)getpid());
        fprintf(stderr, "%d: binary write to stdout OK\n", (int)getpid());
    }

    fprintf(stderr, "%d: 0's = %d, 1's = %d\n", (int)getpid(), zeroes, ones);
    return 0;
}

static void err_exit(char const *fmt, ...)
{
    int errnum = errno;
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    if (errnum != 0)
        fprintf(stderr, "%d: %s\n", errnum, strerror(errnum));
    exit(1);
}

给定一个输入文件:

0101010111111

输出是:

11070: data <<0101010111111>>
11070: forking (l_size = 6, r_size = 7)
11073: right execing with string <<0111111>>
11072: left execing with string <<010101>>
11072: the string is 010101
11072: doing recursion - string too big (6)
11072: forking (l_size = 3, r_size = 3)
11073: the string is 0111111
11073: doing recursion - string too big (7)
11073: forking (l_size = 3, r_size = 4)
11074: left execing with string <<010>>
11075: right execing with string <<101>>
11076: left execing with string <<011>>
11077: right execing with string <<1111>>
11074: the string is 010
11074: doing recursion - string too big (3)
11074: forking (l_size = 1, r_size = 2)
11078: left execing with string <<0>>
11076: the string is 011
11076: doing recursion - string too big (3)
11076: forking (l_size = 1, r_size = 2)
11079: right execing with string <<10>>
11075: the string is 101
11075: doing recursion - string too big (3)
11075: forking (l_size = 1, r_size = 2)
11080: left execing with string <<0>>
11077: the string is 1111
11077: doing recursion - string too big (4)
11077: forking (l_size = 2, r_size = 2)
11082: right execing with string <<11>>
11081: left execing with string <<1>>
11083: right execing with string <<01>>
11084: left execing with string <<11>>
11085: right execing with string <<11>>
11079: the string is 10
11078: the string is 0
11079: read bits, sending back 1 ones and 1 zeroes
11078: read bits, sending back 0 ones and 1 zeroes
11074: binary write to stdout OK
11074: 0's = 2, 1's = 1
11082: the string is 11
11082: read bits, sending back 2 ones and 0 zeroes
11080: the string is 0
11080: read bits, sending back 0 ones and 1 zeroes
11076: binary write to stdout OK
11076: 0's = 1, 1's = 2
11081: the string is 1
11081: read bits, sending back 1 ones and 0 zeroes
11084: the string is 11
11084: read bits, sending back 2 ones and 0 zeroes
11083: the string is 01
11083: read bits, sending back 1 ones and 1 zeroes
11075: binary write to stdout OK
11075: 0's = 1, 1's = 2
11072: binary write to stdout OK
11072: 0's = 3, 1's = 3
11085: the string is 11
11085: read bits, sending back 2 ones and 0 zeroes
11077: binary write to stdout OK
11077: 0's = 0, 1's = 4
11073: binary write to stdout OK
11073: 0's = 1, 1's = 6
11070: 0's = 4, 1's = 9
于 2013-10-13T04:21:50.570 回答