linux应用软件编程之多任务(进程)详解
目录
- 一、多任务概述
- 二、进程概述
- 1.定义
- 2.程序和进程的区别
- 3.进程的产生
- 4.进程的调度
- 5.进程的状态
- 6.进程的消亡
- 三、进程相关的命令
- 1. ps -aux
- 2. top
- 3. ps -ef查看该进程的ID和父进程ID
- 4. pstree查看进程的产生关系
- 5.kill
- 6. jobs查看当前终端的后台进程
- 7.fg
- 四、进程相关的编程
- 1.实现进程的步骤
- 2.进程创建函数
- 3.示例程序
- 3.进程退出函数
- 4.回收资源空间:
- 总结
一、多任务概述
1.定义:
让系统具备同时处理多个任务的能力
2.实现过程
- 多进程
- 多线程
- 进程间通信
二、进程概述
1.定义
一个正在运行的程序称为一个进程,其运行过程中需要消耗内存和CPU。
2.程序和进程的区别
程序 &nbswww.devze.comp; 进程
静态的数据集合,存储在硬盘空间 &编程客栈nbsp; 是一个程序动态执行的过程,需要消耗内存和CPU
程序运行起来可以产生进程 进程具备动态生命周期,从产生到调度再到消亡
一个程序可以产生多个进程 一个进程中也可执行多个程序
3.进程的产生
进程产生时,操作系统都会为其分配0-4G的虚拟内存空间。操作系统内存区如下图所示:
(1)内核: 1 文件管理;2. 进程管;3. 内存管理。
(2)栈区:1.保存局部变量;2.函数的形参和返回值;3.保存函数的调用关系(保护现场和恢复现场)。
(3)堆区:1. 由开发人员手动分配;2. 使用完要手动释放。
(4)数据区:
- data段:1. 已初始化的全局变量 ;2. 已初始化的静态变量。
- bss段:1.未初始化的全局变量 ; 2. 未初始化的静态变量(static)-->bss段初始时按位清0。
- 字符串常量区:保存字符串常量 "hello world"
(5)文本区:1. 存放指令代码 hpp; ;2. 存放常量。
4.进程的调度
- CPU:
由于CPU数据处理速度快,因此是“宏观并行,微观串行”。
- cpu调度算法
1、时间片轮询算法
2、先来先服务,后来后服务(任务队列)
3、短作业优先调度
4、高优先级先执行,低优先级后执行
5.进程的状态
- 操作系统的三态图:
- linux操作系统的进程状态:
- 各进程状态:
1.运行态(用户运行态、内核运行态) R
正在执行,且被CPU任务调度所执行的进程
2.就绪态 R
正在执行,没有CPU任务调度执行的进程(只缺少cpu)
3.可唤醒等待态 S
也称为睡眠态,阻塞等待资源的进程
4.不可唤醒等待态 D
不想被CPU任务调度所打断的进程任务可以设置为不可唤醒等待态
5.暂停态 T
被暂停执行的进程
6.僵尸态 Z
进程执行结束,空间没有被回收
7.结束态 X
进程执行结束,空间被回收
6.进程的消亡
- 进程执行结束(进程退出)
- 回收进程资源空间
三、进程相关的命令
- 父进程:产生子进程的进程称为父进程
- 子进程:父进程产生出来的新进程即为该父进程的子进程
1. ps -aux
查看进程相关参数:PID、状态、CPU占有率、内存占有率
- USER:创建者
- PID:进程的ID号
- %CPU:CPU占有率
- %MEM:内存占有率
- TTY:当前进程所关联的终端
- STAT:当前进程的状态值(带“+”号表示前台进程,不带“+”号表示后台进程)
- START TIME:进程创建的时间
- COMMAND:进程的名称(init进程是操作系统启动的第一个进程)
ps -aux | grep ./a.out
- |:管道 :前面命令的输出作为后面命令的输入
- grep:字符串查找:在输入中查找和后面字符串相关的数据
2. top
动态查看进程的相关参数:CPU占有率、内存占有率
——按照CPU、内存占有率的高低进行排列的
- PR、NI:表示进程的优先级,值越小,优先级越高
- TIME+:进程运行的时间
3. ps -ef查看该进程的ID和父进程ID
4. pstree查看进程的产生关系
pstree -p
查看进程的产生关系(有PID号)
pstree -sp 进程PID号
查看某个指定的进程的产生关系
5.kill
kill -信号的编号/信号的名称 PID
向进程发送信号,让进程的状态发生变化
由第一张图片中可以看出20429进程一开始是在R+运行状态python,执行kill相关命令,其进程被杀死。
结束一个进程的三种表示形式:
kill -9 PID kill -SIGKILL PID killall -9 进程名称
kill -l
查看系统支持的信号
- 9——SIGKILL——杀死信号
- 19——SIGSTOP——暂停态信号
- 18——SIGCONT——唤醒信号
+前台进程后台进程
6. jobs查看当前终端的后台进程
7.fg
[ fg 后台进程编号]
让后台进程切换成前台进程
四、进程相关的编程
1.实现进程的步骤
进程创建 : fork()
- getpid():获取当前进程自己的PID号
- getppid():获取当前进程父进程的PID号
进程调度:操作系统完成
进程消亡:
- 1.进程退出:return、exit()相关函数
- 2.回收资源空间:wait()、waitpid()
2.进程创建函数
pid_t fork(void);
功能:通过拷贝父进程产生一个新的子进程
- 子进程完全拷贝父进程0-3G的虚拟内存空间
- 子进程拷贝父进程PCB(进程控制块)块中的部分内容:PID不拷贝
返回值:
- >0:父进程 ,是子进程的PID号
- ==0:子进程
- -1 :出错
3.示例程序
使用fork函数创建新进程,
- 父进程打印自己的PID和自己子进程的pid
- 子进程中打印自己的PID和父进程的PID
#include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> int main(int argc , const char *argv[]) { pid_t pid = fork(); if(pid > 0) { while(1) { printf("I am father pid = %d sonpid = %d \n",getpid(),pid); sleep(1); } } else if(0 == pid) { while(1) { printf("I am son pid = %d ppid = %d \n",getpid(),getppid()); sleep(1); } } else { perror("fork error"); } return 0; }
注意:
1. 子进程完完整整拷贝父进程0-3G虚拟内存空间。
2. 父子进程栈区、数据区、文本区、堆区完全独立,数据不共享
3. 要想共享数据,需要使用进程间通信方式实现
例如以下程序:
#include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> int main(int argc , const char *argv[]) { pid_t pid = fork(); int num = 0; if(pid > 0) { num = 100; while(1) { printf("I am father pid = %d sonpid = %d num = %d\n",getpid(),pid,num); sleep(1); } } else if(0 == pid) { num = 1000; while(1) { printf("I am son pid = %d ppid = %d num = %d\n",getpid(),getppid(),num); sleep(1); } } else { perror("fork error"); } return 0; }
运行结果如下:
3.进程退出函数
(1)main中return
#include <stdio.h> #include <stdlib.h> int fun() { return 0; } int main(int argc, const char *argv[]) { int i = 15; while (i--) { printf("PID =http://www.devze.com %d\n", getpid()); sleep(1); } return 0; }
(2) exit ()、_exit() :结束一个进程
- exit (0) : 正常退出
- exit (非0) :由于进程产生了某种问题,需要主动退出进程
#include <stdio.h> #include <stdlib.h> int fun() { exit(0); return 0; } int main(int argc, const char *argv[]) { fun(); printf("hello world\n"); return 0; }
4.回收资源空间:
wait()、waitpid()
僵尸进程:进程退出后,但其资源空间未被父进程回收
如何避免僵尸进程产生:
1. 子进程退出后,父进程及时为其回收资源空间
2. 让该进程成为一个孤儿进程,结束时被操作系统中的系统进程回收
孤儿进程:父进程先消亡,其对应的子进程成为一个孤儿进程,会被系统进程所收养
(守护类的进程)
#include <sys/types.h> #include <unistd.h> #include <stdio.h> int main(int argc, const char *argv[]) { pid_t pid = fork(); if (pid > 0) { while (1) { printf("I am father : pid = %d, sonpid = %d\n", getpid(), pid); sleep(1); } } else if (0 == pid) { int i = 15; while (i--) { printf("I am son : pid = %d, ppid = %d\n", getpid(), getppid()); sleep(1); } } else { perror("fork error"); } return 0; }
#include <sys/types.h> #include <unistd.h> #include <stdio.h> int main(int argc, const char *argv[]) { pid_t pid = fork(); if (pid > 0) { int i = 10; while (i--) { printf("I am father : pid = %d, sonpid = %d\n", getpid(), pid); sleep(1); } } else if (0 == pid) { int i = 20; while (i--) { printf("I am son : pid = %d, ppid = %d\n", getpid(), getppid()); sleep(1); } } else { perror("fork error"); } return 0; }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。
精彩评论