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 以下の場合にのみ文字列を読み取ります。
  • 親は左と右の両方の子を作成し、どちらも文字列の半分を作業に使用します

最初にいくつかの簡単な質問をすると思います。

  • select() と execl() を適切に使用していますか?
  • read() と write() を適切に使用していますか?
  • 私が見逃しているメインプロセスに出口はありますか?
  • 両方の子供がパイプを正しく使用して作業していますか?
  • (あまり重要ではありません) 文字列の奇妙な文字が私のカウントを台無しにしていますか? それはどういうわけか私の文字列の中にヌルターミネーターですか?
4

1 に答える 1

1

これは、割るのが難しいナッツの1つです。コードはあいまいな仕事をしており、かなりあいまいに書かれています。私が知る限り、それは と呼ばれることになってmy_programおり、単一の引数としてファイル名で呼び出される予定です。次に、プロセスはファイルを開き、その内容を 2 つの配列 (leftright) に読み込みますが、それらが文字列であることを確認する必要はありません (null 終端はありません)。その後、プロセスは 2 回分岐します。次にleft、引数として(非) 文字列とそれが正しいという情報を使用しleftて自分自身を実行しright、引数として (非) 文字列とそれが正しいという情報を使用して自分自身を実行します。親プロセスが混乱するselect()正当な理由もなく、戻り値をチェックせずに。次に read を呼び出して、2 つのパイプに関する情報を取得します。これらの読み取りは、データの準備が整うまでブロックされるため、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 に答える