Unix进程的学习
一、初步了解父子进程的特性,特别是fork()函数的使用:
- 调用一次,返回两次
- 并发执行
- 相同但是独立的地址空间
- 共享文件
??示例程序如下所示:
#include "csapp.h"
int main(int argc, char** argv){
pid_t pid;
int x = 1;
pid = Fork();
if (pid == 0){
printf("child : x = %d\n", ++x);
exit(0);
}
printf("parent: x = %d\n", --x);
exit(0);
return 0;
}
??运行结果如下所示:
$$$ ./make.sh 1.fork.cpp
parent: x = 0
child : x = 2
??结果说明:
- perent对应的x为0,child对应的x为2。说明父子进程拥有相同但是独立的地址空间,每个继承拥有相同的用户栈、本地变量值、堆、全局变量值、代码,但是都是自己的私有地址空间。
- printf()的输出是在同一个终端。这个表示了共享文件的特性,子进程继承了父进程所有的打开文件,所以输出到同一终端
二、fork()的嵌套使用:
??示例程序如下所示:
#include "csapp.h"
int main(int argc, char** argv){
pid_t pid1;
pid_t pid2;
pid1 = Fork();
pid2 = Fork();
printf("hello--->pid1 = %d--->pid2 = %d\n", pid1, pid2);
return 0;
}
??运行结果如下所示:
$$$ ./make.sh 2.more_fork.c
hello--->pid1 = 4969--->pid2 = 4970
hello--->pid1 = 0--->pid2 = 4971
hello--->pid1 = 0--->pid2 = 0
hello--->pid1 = 4969--->pid2 = 0
??结果说明:
main
fork
pid1=4969
pid1=0
fork
pid2=4970
pid2=0
fork
pid2=4971
pid2=0
printf
printf
printf
printf
三、fork()的相关练习:
??预演如下所示代码父子进程的输出:
#include "csapp.h"
int main(int argc, char** argv){
int x = 1;
if (Fork() == 0){
printf("p1:x=%d\n", ++x);
}
printf("p2:x=%d\n", --x);
exit(0);
}
??本人想象结果如下:
p2:x=0
p1:x=2
p2:x=1
??运行结果如下所示:
$$$ ./make.sh 3.practise.c
p2:x=0
p1:x=2
p2:x=1
四、fork()的相关练习:
??预演如下所示代码所有可能的输出:
#include "csapp.h"
int main(int argc, char** argv){
if(Fork() == 0){
printf("a");
fflush(stdout);
}else{
printf("b");
fflush(stdout);
waitpid(-1, NULL, 0);
}
printf("c");
fflush(stdout);
exit(0);
}
??本人想象结果如下:
bc
ac
bacc
abcc
acbc
??运行结果如下所示:
$$$ ./make.sh 4.practise.c
bacc
五、waitpid的示例:
??预演如下所示代码所有可能的输出:
#include "csapp.h"
#define N 20
#define MIN(a,b) ((a>b)?b:a)
int main(int argc, char** argv){
int status, i;
pid_t pid;
for (i = 0; i < N; i++){
if((pid = Fork()) == 0){
srand(time(0));
sleep(MIN(rand(), 4));
exit(100+i);
}
}
while((pid = waitpid(-1, &status, 0)) > 0){
if (WIFEXITED(status)){
printf("child %d terminated normally with exit status=%d\n", pid, WEXITSTATUS(status));
}else{
printf("child %d terminated abnormally\n", pid);
}
}
if(errno != ECHILD){
unix_error("waitpid error");
}
exit(0);
}
??运行结果如下所示:
$$$ ./make.sh 5.waitpid.c
child 13351 terminated normally with exit status=100
child 13352 terminated normally with exit status=101
child 13353 terminated normally with exit status=102
child 13354 terminated normally with exit status=103
child 13355 terminated normally with exit status=104
child 13356 terminated normally with exit status=105
child 13357 terminated normally with exit status=106
child 13358 terminated normally with exit status=107
child 13359 terminated normally with exit status=108
child 13361 terminated normally with exit status=110
child 13363 terminated normally with exit status=112
child 13364 terminated normally with exit status=113
child 13360 terminated normally with exit status=109
child 13365 terminated normally with exit status=114
child 13366 terminated normally with exit status=115
child 13367 terminated normally with exit status=116
child 13368 terminated normally with exit status=117
child 13369 terminated normally with exit status=118
child 13370 terminated normally with exit status=119
child 13362 terminated normally with exit status=111
六、waitpid同步等待的示例:
??预演如下所示代码所有可能的输出:
#include "csapp.h"
#define N 20
#define MIN(a,b) ((a>b)?b:a)
int main(int argc, char** argv){
int status, i;
pid_t pid[N], retpid;
for (i = 0; i < N; i++){
if((pid[i] = Fork()) == 0){
srand(time(0));
sleep(MIN(rand(), 4));
exit(100+i);
}
}
i = 0;
while((retpid = waitpid(pid[i++], &status, 0)) > 0){
if (WIFEXITED(status)){
printf("child %d terminated normally with exit status=%d\n", retpid, WEXITSTATUS(status));
}else{
printf("child %d terminated abnormally\n", retpid);
}
}
if(errno != ECHILD){
unix_error("waitpid error");
}
exit(0);
}
??运行结果如下所示:
$$$ ./make.sh 6.waitpid_async.c
child 13789 terminated normally with exit status=100
child 13790 terminated normally with exit status=101
child 13791 terminated normally with exit status=102
child 13792 terminated normally with exit status=103
child 13793 terminated normally with exit status=104
child 13794 terminated normally with exit status=105
child 13795 terminated normally with exit status=106
child 13796 terminated normally with exit status=107
child 13797 terminated normally with exit status=108
child 13798 terminated normally with exit status=109
child 13799 terminated normally with exit status=110
child 13800 terminated normally with exit status=111
child 13801 terminated normally with exit status=112
child 13802 terminated normally with exit status=113
child 13803 terminated normally with exit status=114
child 13804 terminated normally with exit status=115
child 13805 terminated normally with exit status=116
child 13806 terminated normally with exit status=117
child 13807 terminated normally with exit status=118
child 13808 terminated normally with exit status=119
七、waitpid的相关练习:
??预演如下所示代码所有可能的输出:
#include "csapp.h"
#define N 20
#define MIN(a,b) ((a>b)?b:a)
int main(int argc, char** argv){
int status;
pid_t pid;
printf("Hello\n");
pid = Fork();
printf("%d\n", !pid);
if (pid != 0){
if (waitpid(-1, &status, 0) > 0){
if (WIFEXITED(status) != 0){
printf("%d\n", WEXITSTATUS(status));
}
}
}
printf("Bye\n");
exit(2);
}
??本人想象结果如下:
Hello
0
2
Bye
1
Bye
Hello
0
1
Bye
2
Bye
Hello
1
0
Bye
2
Bye
??运行结果如下所示:
$$$ ./make.sh 7.practise.c
Hello
0
1
Bye
2
Bye
八、execve()执行命令的示例:
??execve和fork配合使用的代码命令:
#include "csapp.h"
#define MAXARGS 128
int builtin_command(char** argv){
if (!strcmp(argv[0], "quit")){
exit(0);
}else if (!strcmp(argv[0], "&")){
return 1;
}
return 0;
}
int parseline(char* buf, char** argv){
char* delim;
int argc;
int bg;
buf[strlen(buf)-1] = ' ';
while(*buf && (*buf == ' '))
buf++;
argc = 0;
while((delim = strchr(buf, ' '))){
argv[argc++] = buf;
*delim = '\0';
buf = delim + 1;
while(*buf && (*buf == ' '))
buf++;
}
argv[argc] = NULL;
if (argc == 0)
return 1;
if((bg = (*argv[argc -1] =='&')) != 0)
argv[--argc] = NULL;
return bg;
}
void eval(char* cmdline){
char* argv[MAXARGS];
char buf[MAXARGS];
int bg;
pid_t pid;
strcpy(buf, cmdline);
bg = parseline(buf, argv);
if (argv[0] == NULL)
return;
if(!builtin_command(argv)){
if((pid = Fork()) == 0){
if (execve(argv[0], argv, environ) < 0){
printf("%s: Command not found.\n", argv[0]);
printf("Then using execvp command\n");
execvp(argv[0], argv);
exit(0);
}
}
if(!bg){
int status;
if(waitpid(pid, &status, 0) < 0){
unix_error("waitfg: waitpid error");
}else{
printf("%d %s", pid, cmdline);
}
}
return;
}
}
void print_variable(char* name){
printf("%s=%s\n", name, getenv(name));
return;
}
int main(int argc, char** argv){
print_variable("PATH");
char cmdline[MAXARGS];
while(1){
printf(">");
Fgets(cmdline, MAXARGS, stdin);
if (feof(stdin)){
exit(0);
}
eval(cmdline);
}
return 0;
}
??代码说明:
- execve跟fork的区别在于:execve没有创建新的进程,就是完全覆盖了原来的进程程序
- execve跟execvp的区别:前者无法使用到环境变量中的PATH信息,而后者可以利用到,所以后者可以执行类似于ls等命令
??运行结果如下所示:
$$$ ./make.sh 7.practise.c
>ls .
ls: Command not found.
Then using execvp command
test
4741 ls .
>pwd
pwd: Command not found.
Then using execvp command
/media/inspur/inference/pengzhikang/unix_learning/pthread/build/release
4768 pwd
>
|