任务:1. 用C语言写一个rgen.c,是一个random generator,产生的东西是assignment1(python script)的input。(assignment1的input是这样的:
a "Weber Street" (2,-1) (2,2) (5,5) (5,6) (3,8)
a "King Street S" (4,2) (4,8)
a "Davenport Road" (1,4) (5,8)
g
用户输入了以后就会generate一个ouput如下:
)
2. assignment1的output是这样的:
V = {
1: (2,2)
2: (4,2)
3: (4,4)
4: (5,5)
5: (1,4)
6: (4,7)
7: (5,6)
8: (5,8)
9: (3,8)
10: (4,8)
}
E = {
<1,3>,
<2,3>,
<3,4>,
<3,6>,
<7,6>,
<6,5>,
<9,6>,
<6,8>,
<6,10>
}
修改这个output,使其格式为assignment2的input的格式(assignment2的input格式为:
V 15
E {<2,6>,<2,8>,<2,5>,<6,5>,<5,8>,<6,10>,<10,8>}
)
3. 用C语言写一个driver程序。将rgen的ouput送给assignment1,将assignment1的output送给assignment2,然后用户可以输入两个点然后程序返回最短路径。
sample running screenshot:
“V =” 和 “E = ” 后面的东西是经rgen随机产生assignment1可以接受的input之后,经过assignment1处理然后打印出assignment2可以接受的input之后assignment2打印出来的 。
注意事项:1. assignment3是要接受commandline arguments(其实是rgen所需要的参数,全都optional,optional的话就用预设值)的,然后传给rgen。这里不多说参数都干什么的了。
2. 如果rgen随机产生数据,连续25次都没成功,就报错退出,如sample running screenshot所示。
别的不多说!开始总结知识点:
1. rgen.c中。我们需要随机产生一些数据。此次assignment要求必须使用/dev/urandom下的数据。 还有一个文件与urandom类似的叫random。区别见这里:http://blog.csdn.net/wind19/article/details/8085164
一个对这次assignment有用的区别是urandom可以一次读完,而random只能一次读一个byte。好像是这样。本次assignment用法:
int gen_random(int lower, int upper){
unsigned int random;
int random_fd = -1;
if((random_fd = open("/dev/urandom", O_RDONLY)) < 0){
fprintf(stderr, "Error: open /dev/urandom error\n");
exit(1);
}
read(random_fd, &random, sizeof(unsigned int));
random %= (upper - lower + 1); random += lower;
close(random_fd);
return random;
}
后面的求余数操作是因为我们想要得到[a,b] 范围内的一个随机整数。
2.rgen中需要对产生的随机的数据进行查验。 防止产生的两条line segment重叠。 我们检查两条线段是否重叠的方法是:
假设第一条线段的两个端点a,b。第二条线段的两个端点为c,d。
先看abc共不共线,若不共线,则不重叠。若共线,
再看abd共不共线,若不共线,则不重叠。若共线,
再看哪条线长,如果ab长,看c在不在ab中(不包含a,b),若在,则重叠,若不在,如果d在ab中(不包含a,b),则也一定重叠。
如果cd长,方法同上。
如果一样长,如果a,b和c,d分别相同,则点重叠,线段重叠。不相同,方法同上。
看哪条线长 的原因是因为有可能cd包在ab之中,也有可能ab包在cd之中,这样就不知道该用那个点去检测在不在另一条线段中间了。
3. driver中。用管道(重定向输入输出)+ (fork+exec)的方法将各个进程的输入输出串起来。
注意:由于重定向输入输出,可能有内容没能及时到管道中,而是在缓冲区中,这时需要用fflush(stdout)。而我选择的是关掉stdout的缓冲区:
setvbuf(stdout, NULL, _IONBF, 0);
在子进程结束后,会发SIGCHLD信号给父进程,父进程可以在任何地方写一个:
signal(SIGCHLD, sig_handler);
sig_handler是个函数名,随便起名,用来处理这个信号。我写的函数为:
void sig_handler(int sig){
if(sig == SIGCHLD){
kill(pid1, SIGTERM);
kill(pid3, SIGTERM);
exit(0);
}
}
如果有子进程结束,则父进程要结束其他子进程,并且自己退出。
管道重定向+fork+exec核心代码为:
<span style="white-space:pre"> </span>if(pipe(pipe_fd1) < 0){
fprintf(stderr, "Error: pipe failed\n");
exit(-1);
}
if(pipe(pipe_fd2) < 0){
fprintf(stderr, "Error: pipe failed\n");
exit(-1);
}
pid1 = fork();
if(pid1 < 0){
fprintf(stderr, "Error: fork() failed\n");
exit(-1);
}
// first child process handles python
if(pid1 == 0){
close(pipe_fd1[1]);//close write port of pipe1
close(0);//close stdin, prepare for redirection
dup(pipe_fd1[0]);//redirect stdin to read port of pipe1
close(pipe_fd1[0]);// after redirection, close write port of pipe1
close(pipe_fd2[0]);
close(1);
dup(pipe_fd2[1]);
close(pipe_fd2[1]);
// parent of the second child process, execute python script
execvp(comArgv2[0], comArgv2);
fprintf(stderr, "Error: %s: program not found\n", comArgv2[0]);
exit(-1);
}
pid2 = fork();
if(pid2 < 0){
fprintf(stderr, "Error: fork() failed\n");
exit(-1);
}
// second child process handles rgen
if(pid2 == 0){
close(pipe_fd1[0]);
close(1);
dup(pipe_fd1[1]);
close(pipe_fd1[1]);//newly added
execvp(comArgv1[0], comArgv1);
fprintf(stderr, "Error: %s: program not found\n", comArgv1[0]);
exit(-1);
}
if((pid3 = fork()) > 0){
close(pipe_fd2[0]);
close(1);
dup(pipe_fd2[1]);
close(pipe_fd2[1]);
while((fgets(readStr, SIZE, stdin)) != NULL){
printf("%s\n", readStr);
}
kill(pid2, SIGTERM);
kill(pid1, SIGTERM);
kill(pid3, SIGTERM);
}
if(pid3 == 0){
close(pipe_fd2[1]);
close(0);
dup(pipe_fd2[0]);
close(pipe_fd2[0]);
execvp(comArgv3[0], comArgv3);
fprintf(stderr, "Error: %s: program not found\n", comArgv3[0]);
exit(-1);
}