C-未使用fork()、pipe()、select()、execl()和write()到达正确的结尾
我使用分叉和管道来查找文件中字符串中的1和0的数量。然而,我从来没有达到我的程序的正确的目的,即计算1和0。这是一个相当小的代码量,所以这里是整个程序:C-未使用fork()、pipe()、select()、execl()和write()到达正确的结尾,c,multithreading,select,fork,pipe,C,Multithreading,Select,Fork,Pipe,我使用分叉和管道来查找文件中字符串中的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) {
#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;
}
有几个要点可以让您更轻松地理解代码:
- argc在子级中执行时仅为3
- 只有当字符串小于或等于2时,子级才会读取该字符串,否则会再次递归地将字符串切成两半(并生成更多子级)
- 父母同时创造了一个左右两个孩子,两个孩子都承担了一半的工作
- 我是否正确使用select()和execl()
- 我是否正确使用read()和write()
- 我缺少的主要流程是否存在出口
- 两个孩子是否都正确地操作和使用管道
- (不太重要)是字符串中的奇怪字符弄乱了我的计数吗?在我的字符串中有一个空终止符吗
- 这是一个更难破解的螺母。这段代码做的是一项晦涩难懂的工作,写得相当晦涩难懂。据我所知,它应该被称为
my_program
,并且应该用一个文件名作为单个参数来调用。然后,该过程将打开文件,将其内容读入两个数组(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);
}
输出为:
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
11070:数据
11070:分叉(l_尺寸=6,r_尺寸=7)
11073:使用字符串右执行
11072:使用字符串左执行
11072:字符串是010101
11072:执行递归-字符串太大(6)
11072:分叉(l_尺寸=3,r_尺寸=3)
11073:字符串是011111
11073:执行递归-字符串太大(7)
11073:分叉(l_尺寸=3,r_尺寸=4)
11074:使用字符串左执行
11075:使用字符串右执行
11076:使用字符串左执行
11077:使用字符串右执行
11074:字符串是010
11074:执行递归-字符串太大(3)
11074:分叉(l_尺寸=1,r_尺寸=2)
11078:使用字符串左执行
11076:字符串是011
11076:执行递归-字符串太大(3)
11076:分叉(l_尺寸=1,r_尺寸=2)
11079:使用字符串右执行
11075:字符串是101
11075:执行递归-字符串太大(3)
11075:分叉(l_尺寸=1,r_尺寸=2)
11080:使用字符串左执行
11077:字符串是1111
11077:执行递归-字符串太大(4)
11077:分叉(l_尺寸=2,r_尺寸=2)
11082:使用字符串右执行
11081:使用字符串左执行
11083:使用字符串右执行
11084:使用字符串左执行
11085:使用字符串右执行
11079:字符串是10
11078:字符串是0
11079:读取位,返回1个1和1个0
11078:读取位,发送回0个1和1个0
11074:二进制写入标准输出正常
11074:0=2,1=1
11082:字符串是11
11082:读取位,发送回2个1和0个0
11080:字符串为0
11080:读取位,发送回0个1和1个0
11076:对标准输出的二进制写入正常
11076:0=1,1=2
11081:字符串是1
11081:读取位,发送回1个1和0个0
11084:字符串是11
11084:读取位,返回2个1和0个0
11083:字符串是01
11083:读取位,发送回1个1和1个0
11075:二进制写入标准输出正常
11075:0=1,1=2
11072:二进制写入标准输出正常
11072:0=3,1=3
11085:字符串是11
11085:读取位,返回2个1和0个0
11077:二进制写入标准输出正常
11077:0=0,1=4
11073:二进制写入标准输出正常
11073:0=1,1=6
11070:0=4,1=9
请发布编译无错误的代码:int zeroes=*leftR+*righter代码>生成错误,因为leftR
和righter
都不是指针。下一行也有类似的抱怨。修正了,很抱歉。我可能不会用“修正”这个词。此代码:intrights=(int)&rightR;int lefts=(int)&leftR;整数零=左+右;int one=(int)(&leftR+sizeof(int))+(int)(&rightR+sizeof(int))代码>异常-而且极不可能是正确的。将两个地址相加会产生垃圾,而不是答案。我不确定你认为(&leftR+sizeof(int))
会产生什么,但这不是“定义的行为”。此外,鉴于leftR
和rightR
都是单个整数,代码读取(leftPipe[0],&leftR,sizeof(int)*2);读取(右管道[0],&右管道,尺寸(整数)*2)
将两个int
值读入每个单个整数中保证是未定义的行为。是的,这是最肯定的情况。主要的问题是我的程序甚至没有到达最后一个区域,我甚至无法正确地调试它。本质上,(&leftR+sizeof(int))
应该从从从左子级传递的数组位计数器中取出下一个元素。不管怎样,我对一个
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