基于Linux的进程编程 | C/C++

一、进程的基本概念

1.进程的定义

进程是描述程序执行过程和资源共享的基本单位

主要目的:控制和协调程序的执行

2.linux下进程相关函数

用户与组ID:参阅上一讲:https://blog.****.net/qq_38801934/article/details/103142068

创建进程:system(),fork(),exec()

终止进程:kill()

等待进程终止:wait(),waitpid()

3.进程组

由一个或者多个相关进程组成,目的是为了进行作业控制。

进程组的主要特征:信号可以发送给进程组中的所有进程,并使该进程组中的所有进程终止、停止或运行。

每个进程组都属于某个进程组

4.进程组函数

获取进程组ID:pid_t getpgid(pid_t pid);

  • 返回pid进程的进程组ID;若pid为0,则返回当前进程的进程组ID;出错时返回-1,并设有errno值。

设置进程组ID:int setpgid(pid_t pid,pid_t pgid);

  • 若pid为0,则使用调用者PID;若pgid为0,则将pid进程的进程PID设为进程组ID;成功时返回0,出错时返回-1,并设errno值。

5.会话(session)

  • 会话为一个或多个进程组的集合,包括登录用户的全部活动,并具有一个控制终端
  • 登录进程为每各用户创建一个会话,用户登录shell进程成为会话首领,其PID设为会话ID
  • 非会话首领进程通过调用setid()函数创建新会话,并成为首领

进程组函数

获取会话ID:pid_t getsid(pid_t pid);

  • 返回pid进程的会话ID;若pid为0,则返回当前进程会话ID;成功时返回会话ID,出错时返回-1,并设errno值。

设置会话ID:pid_t setsid();

  • 成功时返回新创建的会话ID,出错时返回-1,并设errno值

二、信号(signal):是一种进程通讯机制

  • 信号量是发送给进程的特殊异步消息
  • 当进程接受到信息时立即处理,此时并不需要完成当前函数调用甚至当前代码行。
  • LInux操作系统中有多种信号,具有不同的含义;系统以数字标识不同的信号,程序一般以名称引用信号;

系统信号

  • 系统信号缺省时处理逻辑:终止进程;生成内核转储文件;忽略
  • 使用“kill -l”命令可查看操作系统支持的信号列表,不同的系统可能有所不同。

进程间发送的信号

  • SIGTERM、SIGKILL:终止进程信号,前者是请求(接收信号的进程可以忽略他),后者是强制终止
  • SIGUSER1、SIGUSER2:用户自定义信号,可用于向进程发送命令

信号处理

  • 进程接受到信号之后,根据信号配置进行处理
  • 缺省配置:在程序没有处理时,确定该信号如何处理
  • 程序处理信号的方式:按照信号处理例程提供的函数指针来调用它所指定的函数
  • sigaction()函数:设置信号配置(需要的时候再详细了解)

基于Linux的进程编程 | C/C++
常用系统信号
基于Linux的进程编程 | C/C++
基于Linux的进程编程 | C/C++
基于Linux的进程编程 | C/C++

信号处理注意事项

  • 信号是一个异步操作,当处理信号时,主程序非常脆弱
  • 信号处理例程尽可能小,它甚至可能会被新信号所中断
  • 尽量不要在信号处理例程中实施I/O操作,也不要频繁调用系统函数或库函数
  • 在信号处理例程中进行复杂的赋值操作也是危险的,他可能不是原子操作,因而有可能在执行期间被中断。
  • 如果需要赋值,使用sig_atomic_t类新的全局变量(在linux中等价于int,亦即允许整数或指针赋值,更大尺寸数据不允许)

三、进程管理

1.进程创建

fork()返回两个值,分别给父子进程用
基于Linux的进程编程 | C/C++

执行命令的基本模式:在程序中调用fork()创建一个子进程,让那后调用exec()在子进程中执行命令。
基于Linux的进程编程 | C/C++
基于Linux的进程编程 | C/C++

2.进程调度

进程调度策略:先进先出,时间片轮转,普通调度,批调度,高优先级优先

  • 子进程与父进程的调度没有固定顺序;不能假设子进程一定会在父进程之后调度,也不能假设子进程一定会在父进程之前结束。

基于Linux的进程编程 | C/C++
基于Linux的进程编程 | C/C++

2.进程终止:kill()

基于Linux的进程编程 | C/C++

3.僵尸进程

  • 子进程已结束,但父进程未调用wait()函数等待
  • 子进程已终止,但没有被正确清除,成为僵尸进程

清除子进程的手段

  • 父进程调用wait()函数可确保子进程被清除
  • 即使子进程在父进程调用wait()函数前已经死亡(成为僵尸),起退出状态也可以被抽取出来,然后被清除
  • 未清除的子进程自动被inti进程领养

4.子进程的异步清除

SIGCHLD信号:子进程终止时,向父进程自动发送编写此信号处理例程,异步清理子进程

5.守护进程

创建守护进程步骤

  • 创建新进程:新进程将成为未来的守护进程
  • 守护进程的父进程退出:保证祖父进程确认父进程已结束,切守护进程不是组长进程
  • 守护进程创建新进程组和新会话:并成为两者的首进程,此时刚创建的新会话还没有关联控制终端
  • 改变工作目录:守护进程一般随系统启动,工作目录不应该继续使用继承的工作目录
  • 重设文件权限掩码:不需要继承文件权限掩码
  • 关闭所有文件描述符:不需要继承任何打开文件描述符
  • 标准流重定向到/dev/null
  • 创建成以根用户权限运行他或者随用户一起启动

守护进程创建函数deamon()

基于Linux的进程编程 | C/C++

6.进程间的通信

6.1 管道:相关进程间的顺序通信

pipe的性质和意义

  • 管道是允许单向通信的自动同步设备(半双工)
  • 数据在写入端写入,在读取端读取
  • 管道为串行设备,数据的读取顺序和写入顺序完全相同

管道的用途

  • 只能用于有亲缘关系的进程,例如父进程和子进程之间通信

注意事项

  • 管道的数据容量有限,一般为一个内存页面
  • 如果写入速读超过读取速读,写入进程将阻塞,知道容量有空闲
  • 如果读取速读超过写入速度,读取进程将阻塞,知道管道有数据

基于Linux的进程编程 | C/C++

管道重定向

基于Linux的进程编程 | C/C++

6.2 进程信号量:进程间通信的同步控制机制(System V信号量)

基于Linux的进程编程 | C/C++

  • 进程信号量用于进程同步

  • POSIX标准实现多线程同步

使用进程信号量注意事项

基于Linux的进程编程 | C/C++

获取进程信号量

基于Linux的进程编程 | C/C++

控制和管理进程信号量

基于Linux的进程编程 | C/C++

清除进程信号量

基于Linux的进程编程 | C/C++

union是共用存储区域,也就是所有的字段只有一个字段有效。

初始化进程信号量

基于Linux的进程编程 | C/C++

信号量的获取与释放

基于Linux的进程编程 | C/C++

信号量的等待与发布

基于Linux的进程编程 | C/C++基于Linux的进程编程 | C/C++

实例

基于Linux的进程编程 | C/C++

6.3 共享内存:允许多个进程读写同一片内存区域

基于Linux的进程编程 | C/C++

LInux内存模型

基于Linux的进程编程 | C/C++

获取共享内存

基于Linux的进程编程 | C/C++

基于Linux的进程编程 | C/C++

连接与拆卸共享内存

基于Linux的进程编程 | C/C++

示例

基于Linux的进程编程 | C/C++

6.4 映射内存:与共享内存意义相同,但与文件相连

基于Linux的进程编程 | C/C++

基于Linux的进程编程 | C/C++
基于Linux的进程编程 | C/C++
6.5 消息队列:在进程间传递二进制块数据

基于Linux的进程编程 | C/C++

基于Linux的进程编程 | C/C++

和进程信号量有类似的地方,需要的时候再查阅

6.6 套接字(socket):支持无关进程,甚至不同计算机进行通信

7.进程池

动机及其概念

基于Linux的进程编程 | C/C++

四、散装知识、问题点

1.真正的操作系统接口只有系统调用接口,其他所谓的图形接口、字符命令行接口都是建立在调用操作系统接口之上

2.红黑树是什么?作用领域在那儿?

数据库领域

3.linux系统中用file 文件名,可以得到file的一些信息。

4.什么是同步什么是异步?

针对不同的对象,如果是线程,那么同步就是两个线程同时使用一个资源;异步就是一个线程在使用资源其它线程等待它释放资源之后在使用。

如果是信号也是同样的道理,信号在等待进程对信号进行处理

5.进程池的工作原理是什么?

基于Linux的进程编程 | C/C++