gpt4 book ai didi

C - 使用 fork()、pipe()、select()、execl() 和 write() 未达到正确的结尾

转载 作者:行者123 更新时间:2023-11-30 15:44:46 25 4
gpt4 key购买 nike

我正在使用 fork 和管道来查找文件内字符串中 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 才会读取该字符串,否则会再次递归地将字符串切成两半(并生成更多子进程)
  • parent 分别创建左 child 和右 child ,都使用一半的字符串来处理

我想首先要解决几个简单的问题:

  • 我是否正确使用了 select() 和 execl() ?
  • 我是否正确使用了 read() 和 write() ?
  • 我缺少的主要进程中是否有导出?
  • 两个 child 都正确地工作和使用管道吗?
  • (不太重要)字符串中的奇怪字符是否扰乱了我的计数?我的字符串中是否有一个空终止符?

最佳答案

这是最难破解的难题之一。该代码正在做一项晦涩的工作,并且编写得相当晦涩。据我所知,它应该被称为 my_program,并且将使用文件名作为单个参数来调用。然后,该进程将打开该文件,将其内容读入两个数组(leftright),而不必费心确保它们是字符串(无空终止)。然后该进程 fork 两次。然后,使用 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

关于C - 使用 fork()、pipe()、select()、execl() 和 write() 未达到正确的结尾,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19340652/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com