暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

D1 - 进程编程及守护进程

西红柿爆炒鸡蛋 2021-07-14
718

第一讲 (了解)

程序磁盘上的指令与数据 (静态)
进程执行程序所分配的资源 (动态) = 静态的程序代码跑起来就是进程
如下图,同一个程序在2个终端分别运行一次就算运行两次,就是两个进程
进程类型前台进程 (平时普通的./a.out)= 程序在前台跑起来
后台进程 (./a.out & 运行时在后面加取地址符'&'就能让程序在后台运行)= 程序在后台跑起来,但是不能接收前台的任何数据
守护进程 = 一直在后台运行的进程
进程状态正在运行
准备运行=就绪
运行起来后,突然中断进行等待
停止态
僵尸态=已经结束的进程,但是pcb没有释放
进程控制块pdb包含
进程身份证PID
进程属于哪个用户
进程状态,优先级
当前进程打开了哪些文件=文件描述符表
......

第二节 (掌握熟练)

| 查看前台进程的指令! | |--|--| | ps aux 查看所有进程
 | |top top=顶,对消耗资源最大的进程进行实时显示
| |在根目录的proc文件中存放的是进程文件
)
这些以PID进程号命名的文件夹里面详细记录了进程信息
|

| 修改用户进程的优先级的方法!(不是修改程序优先级的方法) | |--|--| | nice -n 2 ./a.out 以优先级2来运行a.out
//权限范围[-20,19],一般取大于0,(进程默认优先级0)
| |修改进程/正在运行程序的优先级 = renice
|

| 后台进程相关命令 | |--|--| | jobs 查看后台进程
fg 将后台进程切换到前台运行
bg将前台进程切换到后台运行
ctrl + z 暂停进程
//注:(由于后台进程无法直接暂停,需要先切换到前台进程进行暂停,再切换到后台继续后台运行)

第三讲

3.1 创建子进程 fork() 与 结束进程 exit(0)


结束进程不等于释放进程资源,父进程在判断到子进程exit(0)结束进程后,父进程才会判断到子进程


子进程就算盗版的父进程,两者几乎一样,但是盗版的没有正名,还是有进程号,子进程需要正版的父进程对其进行回收


子进程就是父进程完全copy一份出来就是子进程,但是他们是两个独立的互不影响的进程,父子进程的进程号PID不一样,每个进程结束后,必须由父进程进行回收,如果父进程先结束,子进程成为孤儿进程(孤儿进程没排面,不能在前台运行,所有变成后台进程),,被init进程(进程号=1)收养;但是如果父进程没有先结束,但是却没有对结束的子进程进行回收,那么子进程就会狂暴变成僵尸进程,要避免


子进程如何开始运行? 答:父进程从main函数开始运行,当父进程在10行代码处使用fork函数创建了子进程后,此时PC指向第11行代码,父子进程都从第11行开始向下执行


fork返回值是pid_t类型是一个特殊的int类型 1:当判断到当前进程是父进程,pid_t的值就是被创建的进程的进程号,>0 2:当判断到当前进程就是被创建的子线程,那么就返回0 3:如果没有子线程没有创建成功,那么pid_t的值就是<0

  • getpid() 获取当前进程的进程号

  • 父进程多次调用fork可以创建多个子进程

  • 子进程也能调用fork创建孙子进程😂

  • exit结束进程时,会将进程中流的缓冲区刷新/推出

 10 在父线程中创建子线程,并且查看两个线程的pid进程号
11 ================================================================*/
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <strings.h>
16 #include <unistd.h>
17 #include <unistd.h>
18 main()
19 {
20 printf("进入main\n");
21 pid_t Mypid;
22
23 Mypid = fork(); 创建子进程
24
25 printf("创建进程\n");
26 printf("\nMypid = %d",Mypid); 打印子进程的进程号
27
28 if(Mypid<0)
29 {
30 perror("\n创建线程出错!");
31 }
32 else if(Mypid==0)
33 {
34 printf("\n子进程的进程号=%d\n",getpid()); 获取当前进程的进程号
35 }
36 else if(Mypid>0)
37 {
38 printf("\n父进程的进程号=%d",getpid()); 获取当前进程的进程号
39 }
40
41 exit(0); 退出进程
42 }

==>>结果
farsight@ubuntu:~/Desktop$ ./a.out
进入main
创建进程

Mypid = 4609
创建进程
父进程的进程号=4608
Mypid = 0
子进程的进程号=4609

第四讲

4.1 exec函数族之execl函数

注意execl,execlp,execv,execvp,这四个函数都是一个功能,效果都一样,
只需要掌握一个最简单的execl就ok

  • execl函数不是excel那个软件,😂

  • exec能切换到另一个程序,配合子进程可以让父子进程执行不同的程序,解决了子进程与父进程执行一样程序的尴尬

  • execl函数执行指定切换的程序

在上面代码的基础上,创建了子进程后,在子进程运行hello.c编译后的名为hello的可执行文件
11 ================================================================*/
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <strings.h>
16 #include <unistd.h>
17 #include <unistd.h>
18 main()
19 {
20 printf("进入main\n");
21 pid_t Mypid;
22
23 Mypid = fork(); 创建子进程
24
25 printf("创建进程\n");
26 printf("\nMypid = %d",Mypid); 打印子进程的进程号
27
28 if(Mypid<0)
29 {
30 perror("\n创建线程出错!");
31 }
32 else if(Mypid==0)
33 {
34 printf("\n子进程的进程号=%d\n",getpid()); 获取当前进程的进程号
35
36 int ret = execl("/home/farsight/Desktop/hello","这是参数1","这是参数2",NULL);
37 execl函数第一个参数是要被执行的可执行文件的目录
38 execl函数中间的若干参数是要向被执行的main程序传递什么参数,不传就写NULL
39 execl函数最后一个参数写NULL
40
41 if(ret == -1){ execl的返回值=-1,代表程序运行失败!
42 perror("\n程序运行失败!");
43 }
44 }
45 else if(Mypid>0)
46 {
47 printf("\n父进程的进程号=%d",getpid()); 获取当前进程的进程号
48 }
49
50 exit(0); 退出进程
51 }
11
================================================================*/
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <strings.h>
16
17 void main(int argc,char **argv)
18 {
19
20 printf("\n进入hello.c");
21 printf("\n%s",argv[0]);
22 printf("\n%s",argv[1]);
23 }
================================================================*/
结果:
farsight@ubuntu:~/Desktop$ ./a.out
进入main
创建进程

Mypid = 5266
父进程的进程号=5265创建进程

Mypid = 0
子进程的进程号=5266
farsight@ubuntu:~/Desktop$
进入hello.c
这是参数1
这是参数2
================================================================*/

4.2 system函数 system函数 = fork函数 + execl函数 + wait函数

system函数是fork创建子进程函数与execl运行程序函数,这两个函数的结合体,他能够自动创建子进程,并且运行程序,但是不能对程序进行传参,直到子进程结束后,也会自动释放子进程,释放完后父进程才开始继续运行

 11 ================================================================*/
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <strings.h>
16 #include <unistd.h>
17 #include <unistd.h>
18 main()
19 {
20 printf("进入main\n");
21 system("/home/farsight/Desktop/hello");
22
23 exit(0); 退出进程
24 }
11 ================================================================*/
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <strings.h>
16
17 void main(int argc,char **argv)
18 {
19
20 printf("\n进入hello.c");
21 }

================================================================
结果:
farsight@ubuntu:~/Desktop$ ./a.out
进入main

进入hello.c
================================================================

第四讲结论
{
1:如果子进程打开的程序需要进行传参,就只能用fork先创建子进程,
再用execl来运行程序,进行传参

2:如果子进程对打开的程序不需要进行传参,只是运行该程序,
就直接用system函数就ok特别特别方便!
}

第五讲 回收子进程

>>前面介绍了结束进程与创建子进程,还没介绍子进程如何被父进程的回收

5.1 wait函数

wait功能: 1>>等待子进程结束后,将其回收 2>>如果没有结束,父进程就等待其结束,再进行回收 3>>如果父进程下有多个子进程,就需要调用多次wait来回收,wait优先回收先结束的子进程

WIFEXITED = W IF EXIT ED 功能 函数名功能拆解:W=wait();IF如果;EXIT离开;ED: 根据wait函数,依据子进程返回值,判断子进程是否正常结束

  • wait回收成功时返回回收的子进程的进程号>0:失败时返回EOF/-1

  • 由于释放子进程返回子进程的PID与子进程的main的return的返回值;所以wait函数的返回值接收PID,参数用来接收main的return 值

wait函数接收到子进程返回的值后有下面四种处理函数

WIFEXITED宏判断子进程是否正常结束
WEXITSTATUS宏获取子进程的返回值
WIFSIGNALED宏判断子进程是否被信号结束
WTERMSIG宏在WIFSIGNALED宏的基础上,获取结束子进程的信号类型
 10 在父进程中创建子进程,当子进程exit退出后,父进程用wait将其回收,打印回收的子进程的进程号,并用宏根据返回值判断是否回收成功
11 ================================================================*/
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <strings.h>
16 #include <unistd.h>
17 #include <unistd.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 void main()
21 {
22 pid_t son_pid = 0; 接受子进程的进程号
23
24 int son_return = 0; 接受子进程返回的return值
25 printf("进入main\n");
26
27 pid_t pid;
28
29 创建子进程
30 pid = fork();
31
32 if(pid <0 )
33 {
34 perror("\nfork error");
35 }
36 else if(pid == 0)
37 {
38 printf("\n进入子进程");
39 运行程序
40 execl("/home/farsight/Desktop/hello",NULL,NULL);
41 }
42 else if(pid > 0)
43 {
44 printf("\n当前进程为父进程");
45 }
46 等待子进程结束后,将其回收
47 son_pid = wait(&son_return);
48 if(son_pid==-1)
49 {
50 perror("\nwait error : ");
51 }
52 打印父进程获取到的子进程的进程号与返回值
53 printf("\nson_pid = %d \nson_return = %d",son_pid,son_return);
54 if(WIFEXITED(son_return) == 1)
55 {
56 printf("\n子进程正常结束!");
57 }
58
59 exit(0); 退出进程
60 }
11 ================================================================*/
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <strings.h>
16
17 int main(int argc,char **argv)
18 {
19
20 printf("\n子进程>>进入hello.c");
21
22 printf("\n子进程进程号%d\n",getpid());
23 return 88;
24 exit(-1);
25
26 }

================================================================*/
结果:
farsight@ubuntu:~/Desktop$ ./a.out
进入main



子进程>>进入hello.c
子进程进程号3659
当前进程为父进程
son_pid = 3659
son_return = 22528
子进程正常结束!farsight@ubuntu:~/Desktop$



5.2 waitpid函数

  • waitpid函数与wait函数都是释放子进程,唯一的区别的waitpid是回收指定进程

 11 ================================================================*/
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <strings.h>
16 #include <unistd.h>
17 #include <unistd.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 void main()
21 {
22 pid_t son_pid = 0; 接受子进程的进程号
23
24 int son_return = 0; 接受子进程返回的return值
25 printf("进入main\n");
26
27 pid_t pid;
28
29 创建子进程
30 pid = fork();
31
32 if(pid <0 )
33 {
34 perror("\nfork error");
35 }
36 else if(pid == 0)
37 {
38 printf("\n进入子进程");
39 运行程序
40 execl("/home/farsight/Desktop/hello",NULL,NULL);
41 }
42 else if(pid > 0)
43 {
44 printf("\n当前进程为父进程");
45 }
46
47
48 等待子进程结束后,将其回收
49
50 pid:代表回收子进程的进程号
51 son_return接受返回指
52 0代表阻塞式,父进程一直等待子进程结束
53 son_pid = waitpid(pid,&son_return,0);
54 if(son_pid==-1)
55 {
56 perror("\nwait error : ");
57 }
58 打印父进程获取到的子进程的进程号与返回值
59 printf("\nson_pid = %d \nson_return = %d",son_pid,son_return);
60 if(WIFEXITED(son_return) == 1)
61 {
62 printf("\n子进程正常结束!");
63 }
64
65 exit(0); 退出进程
66 }

11 ================================================================*/
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <strings.h>
16
17 int main(int argc,char **argv)
18 {
19
20 printf("\n子进程>>进入hello.c");
21
22 printf("\n子进程进程号%d\n",getpid());
23 return 88;
24 exit(-1);
25
26 }
11 ================================================================*/
结果:
farsight@ubuntu:~/Desktop$ ./a.out
进入main



子进程>>进入hello.c
子进程进程号3891
当前进程为父进程
son_pid = 3891
son_return = 22528
子进程正常结束!

第六讲 守护进程

守护进程守护进程是Lnux三种进程类型之一
守护进程属于特殊后台进程(不依赖终端),一直在后台运行,不会影响其他进程
守护进程周期性的执行某种任务
问:守护进程合适启动?答守护进程在跟随linux系统启动而启动,跟随linux系统关闭而关闭,所以叫守护进程
问:守护进程有什么应用?答:众多TCP/IP的通信协议都是以守护进程的方式进行运行
------
· Linux用会话,进程组来管理全部的进程
----
每个父进程被分配到一个进程组,父进程下的子进程也属于这个进程组
·用户打开一个终端就是打开一个会话,会话包含多个进程组。所有在该终端运行的进程都属于该会话,当终端关闭时,会话也关闭,进而该会话里面的所有前台,后台进程全部关闭

6.1 守护进程的创建

| 步骤1:创建一个孤儿进程(先在父进程中创建子进程,再率先把父进程exit关掉)| |-|-| |步骤2:步骤1过后,这个孤儿进程依然依附于该终端所打开的会话,需要在孤儿进程中自己setsid();创建一个会话,这样孤儿进程就是该会话的第一个进程也就是会话组长,脱离了原来的会话,孤儿进程独立了变成了守护进程; |步骤3:最后我们还没有为会话设置工作路径,使用chdir("/tmp") (/tmp目录专门存放守护进程会话)为守护进程的会话设置工作路径就ok |步骤4:由于守护进程是很特殊的协议类进程,我们需要将守护进程umask(0);对文件的操作的权限设置为最高| |步骤5:由于守护进程最开始是子进程,子进程会继承父进程所打开的文件,由于我们的守护进程脱离了终端,stdin/stdout/stderr这些流不能写入文件了,所以我们需要将守护进程最开始继承父进程的所有文件全部关闭,使用getdtablesize()查看打开的文件个数,使用close(x)进行关闭文件

创建守护进程,每隔2秒将hello word!字符串写入文件mytext.txt
11 ================================================================*/
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <strings.h>
16 #include <unistd.h>
17 #include <unistd.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 void main()
21 {
22 /***********************************创建守护进程******************* ******/
23 int i;
24
25 pid_t hood_pid; //子进程的进程号
26
27 hood_pid = fork(); //创建子进程
28 if(hood_pid>0)
29 {
30 printf("当前是父进程\n");
31 exit(0); //父进程关闭,将子进程沦为孤儿进程
32 }
33 else if(hood_pid == 0)
34 {
35
36 printf("当前是子进程\n");
37 //孤儿进程创建自己的回话成为守护进程
38 setsid();
39
40 //为回话设置工作路径
41 chdir("/tmp");
42 //设置守护进程的文件操作权限
43 umask(0);
44 //关闭所有由父进程继承的已经打开的文件
45 for(i=0;i<getdtablesize();i++)
46 {
47 close(i);
48 }
49
50 /*********************文件操作**********************/
51 FILE *fp;
52 fp = fopen("mytext.txt","a+");
53 if(fp == NULL)
54 {
55 perror("\n文件创建error");
56 exit(0);
57 }
58 else
59 {
60 while(1)
61 {
62 fprintf(fp,"hello word!\n");
63 fflush(fp);
64 sleep(2);
65 }
66
67 }
68 }
69
70 else if(hood_pid <0)
71 {
72 perror("创建子进程错误");
73 }
74 }
================================================================*/

farsight@ubuntu:~/Desktop$ ./a.out

当前是父进程
当前是子进程

运行结果:我们运行父进程后,在父进程中创建了子进程后,将父进程退出,然后我们可以在终端会话中看见父进程退出,
我们打开./tmp这个专门存放守护进程的目录,发现了我们创建的mytext.txt文件,我们可以看见hello word被持续写入文件中,
代表我们的守护进程创建成功,守护进程一直脱离终端被运行

注意:

EOF = -1


文章转载自西红柿爆炒鸡蛋,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论