一。进程创建:
主要用fork()函数创建进程,当调用fork时,内核会做:
(1)分配新的内存块和内核数据结构给子进程。
(2)将父进程部分数据内容拷贝至子进程。
(3)添加子进程到系统进程列表当中。
(4)fork返回,开始调度器调度。
举例:
#include<stdio.h>
2 #include<unistd.h>
3 #include<stdlib.h>
4 #include<sys/types.h>
5
6 int main(void)
7 {
8 pid_t pid;
9 printf("before: pid is %d\n",getpid());
10 if( (pid=fork())==-1)perror("fork()"),exit(1);
11 printf("after:pid is %d,fork return %d\n",getpid(),pid);
12 sleep(10);
13 }
所以,fork之前父进程独立执行,fork之后,父子两个执行流分别执行。
fork的返回值:子进程返回0,父进程返回的是子进程的id。
fork调用失败的原因:(1)系统中有太多的进程。(2)实际用户的进程数超越了限制。
Linux中还有一个vfork函数:
(1)它用于创建一个子进程,而子进程与父进程共享地址空间,fork的子进程具有独立地址空间。
(2)vfork保证子进程先运行,在它调用exec之后父进程才可能被调用。
注:fork不能通过更改子进程中的变量值来改变父进程中的变量值,而vfork可以,因为它的子进程在父进程的地址空间运行。
举例:
#include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4
5 int flag=10;
6 int main(void)
7 {
8 pid_t pid;
9 if((pid=vfork())==-1)perror("fork()"),exit(1);
10 if(pid==0)
11 {
12 sleep(3);
13 flag=1;
14 printf("child flag is %d\n",flag);
15 exit(0);
16 }
17 else{
18 printf("parent flag=%d\n",flag);
19 }
20 }
这是vfork函数应用,结果是:
所以它将父进程的变量值也改变了。
再来看看fork函数:
#include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4
5 int flag=10;
6 int main(void)
7 {
8 pid_t pid;
9 if((pid=fork())==-1)perror("fork()"),exit(1);
10 if(pid==0)
11 {
12 sleep(3);
13 flag=1;
14 printf("child flag is %d\n",flag);
15 exit(0);
16 }
17 else{
18 printf("parent flag=%d\n",flag);
19 }
20 }
[ymk@localhost d3]$ gcc 3.c
[ymk@localhost d3]$ ./a.out
parent flag=10
[ymk@localhost d3]$ child flag is 1
fork没有改变父进程的变量值,而且子进程也是在父进程运行完之后才运行的。
二。进程终止
1.退出场景:
(1)代码运行完毕,结果正确。
(2)代码运行完毕,结果不正确。
(3)代码异常终止。
2.退出方法:
(1)正常终止:从main返回;调用exit;_exit
(2)异常退出:ctrl+c,信号终止;abort();kill;
#include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4
5 int main(void)
6 {
7 while(1)
8 {
9 printf("haha\n");
10 sleep(1);
11 }
12 }
[ymk@localhost d3]$ ps -el | grep a.out
0 S 1000 39619 37604 0 80 0 - 1042 hrtime pts/0 00:00:00 a.out
[ymk@localhost d3]$ kill 39619
[ymk@localhost d3]$ ps -el | grep a.out
[ymk@localhost d3]$
用Kill终止进程。
三。进程等待
1.父进程通过进程等待的方式,回收子进程资源。获取子进程退出信息。
2.wait:回收僵尸进程。
3.waitpi:
pid _t waitpid(pid_t pid,int *status,int options);
(1)pid:pid=-1:等待任何一个子进程死亡,与wait一样。;pid>0:本进程的子进程;pid<-1:|pid|进程组的任一个子进程死亡
pid=0:调用者进程所在进程组的任一个子进程死亡。
(2)status:
WIFEXITED:若为正常终止子进程返回的状态,则为真。
WEXITSTATUS:若WIFEXITED非0,提取子进程退出码。
(3)options:
WNOHANG:若Pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待,若正常结束,则返回子进程id。
注:如果子进程已经退出,调用wait时,会立即返回,释放资源,获得子进程退出信息。
如果在任意时刻调用wait/waited,子进程存在正常运行,则进程可能阻塞。
如果不存在该子进程,则立即出错返回。
4.举例:
#include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/wait.h>
4 #include<unistd.h>
5
6 int main()
7 {
8 pid_t pid;
9 pid=fork();
10 if(pid<0){
11 printf("fork error\n");
12 return 1;
13 }
14 else if(pid==0){
15 printf("child is run,pid is %d\n",getpid());
16 sleep(2);
17 exit(257);
18 }
19 else{
20 int status=0;
21 pid_t r=waitpid(-1,&status,0);
22 printf("this is test for wait\n");
23 if(WIFEXITED(status) && r==pid){
printf("wait child 5s success, child return code is %d\n",WEXITSTATUS(st atus));
25 }
26 else{
27 printf("wait child failed,return \n");
28 return 1;
29 }
30 }
31 return 0;
32 }
[ymk@localhost d3]$ ./a.out
child is run,pid is 40492
this is test for wait
wait child 2s success, child return code is 1
这个父进程等待了2秒才运行。
四。进程替换。
1.exec函数:execvp:不会创建进程,会用参数给定的程序替换当前的进程。
2.举例:
#include<stdio.h>
2 #include<unistd.h>
3 int main(void)
4 {
5 char *argv[]={
6 "ls","-l",NULL};
7 printf("before execvp\n");
8 execvp("ls",argv);
9 printf("after execvp");
10 }
[ymk@localhost day07]$ ./a.out
before execvp
total 40
-rw-rw-r--. 1 ymk ymk 483 Jul 8 20:30 a.c
-rwxrwxr-x. 1 ymk ymk 8656 Jul 8 20:30 a.out
-rw-rw-r--. 1 ymk ymk 425 Jul 8 20:13 i.c
-rw-rw-r--. 1 ymk ymk 304 Jun 30 22:57 o.c
-rw-rw-r--. 1 ymk ymk 278 Jul 1 01:12 p.c
-rw-rw-r--. 1 ymk ymk 933 Jun 30 05:46 s.c
-rw-rw-r--. 1 ymk ymk 170 Jul 8 20:30 x.c
-rw-rw-r--. 1 ymk ymk 299 Jul 8 20:30 z.c
用ls -l代替了输出after execvp 。
五。制作一个简单的shell:
#include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 #include<sys/wait.h>
5 #include<ctype.h>
6 #include<string.h>
7
8 #define MAXLINE 1024
9 char cmdline[MAXLINE+1];
10 int argc=0;
11 char *argv[8];
12
13 void init(void)
14 {
15 argc=0;
16 memset(cmdline,0x00,sizeof(cmdline));
17 }
18
19 int read_cmd()
20 {
21 return fgets(cmdline,MAXLINE,stdin)==NULL?0:1;
22 }
int prase_cmd()
25 {
26 int flag=0;
27 int i;
28 for(i=0;cmdline[i]!='\0';i++)
29 {
30 if(flag==0 && !isspace(cmdline[i])){
31 flag=1;
32 argv[argc]=cmdline+i;
33 argc++;
34 }
35 else if(isspace(cmdline[i])){
36 flag=0;
37 cmdline[i]='\0';
38 }
39 }
40 argv[argc]=NULL;
41 }
int execute_cmd()
44 {
45 if(fork()==0)
46 {
47 execvp(argv[0],argv);
48 exit(1);
49 }
50 }
51
52 void print_cmd()
53 {
54 int i;
55 for(i=0;i<argc;i++)
56 {
57 printf("targv[%d]=%s\n",i,argv[i]);
58 }
59 }
int main(void)
62 {
63 while(1){
64 init();
65 printf("shell >");
66 if(read_cmd()==0)
67 break;
68 prase_cmd();
69 print_cmd();
70 execute_cmd();
71 }
72 }
六。fopen,system与fork区别:
(1)system:在执行期间调用进程会一直等待shell命令执行完成。执行shell命令最后返回是否执行成功,
(2) popen:无须等待shell命令执行完成就返回 (并行执行)。执行命令并且通过管道和shell命令进行通信。
(3)popen后需要调用pclose防止子进程变成”僵尸”状态。
(4)fork :执行期间父进程等待子进程的退出码。
七。封装fork/wait等操作, 编写函数 process_create(pid_t* pid, void* func, void* arg), func回调函数就是子进程执行的入口函数, arg是传递给func回调函数的参数.
#include<stdio.h>
2 #include<unistd.h>
3 #include<sys/wait.h>
4 #include<stdlib.h>
5
6 void process_create(pid_t* pid,void* func,void* argv)
7 {
8 if((*pid=fork())<0){
9 perror("fork()"),exit(1);
10 }
11
12 else if(*pid==0){
13 ((int(*)())func) (((char**)argv)[0],(char**)argv);
14 perror("func");
15 }
16 else{
17 int st;
18 while(wait(&st)!=*pid);
19 }
20 }
21 int main()
22 {
23 pid_t pid;
pid_t pid;
24 char *argv[]={"ls","-l",NULL};
25 process_create(&pid,execvp,argv);
26 return 0;
27 }
[ymk@localhost d3]$ ./a.out
total 56
-rw-rw-r--. 1 ymk ymk 274 Jul 8 19:13 1.c
-rw-rw-r--. 1 ymk ymk 282 Jul 8 19:38 2.c
-rw-rw-r--. 1 ymk ymk 282 Jul 8 19:46 3.c
-rw-rw-r--. 1 ymk ymk 124 Jul 8 19:52 4.c
-rw-rw-r--. 1 ymk ymk 602 Jul 8 20:27 5.c
-rw-rw-r--. 1 ymk ymk 148 Jul 8 20:35 6.c
-rw-rw-r--. 1 ymk ymk 933 Jul 8 21:13 7.c
-rw-rw-r--. 1 ymk ymk 434 Jul 8 21:27 8.c
-rwxrwxr-x. 1 ymk ymk 8792 Jul 8 21:27 a.out
-rw-rw-r--. 1 ymk ymk 1277 Jul 7 23:17 p.c
-rw-rw-r--. 1 ymk ymk 933 Jul 8 20:58 s.c
-rw-rw-r--. 1 ymk ymk 982 Jul 8 21:12 shell.c
以上就是进程的各种操作及应用。