1.共享内存通信
1>共享内存指在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存。
2>概述:共享内存是进程间通信中最简单的方式之一。顾名思义就是允许两个不相关的进程
访问同一个逻辑内存,共享内存是两个正在运行的进程 之间共享和传递数据的一种非常有效的方
式。不同进程之间共享的内存通常为同一段物理内存。进程可以将同一段物理内存连接到他们自己
的地址空间中,所有的进程都可以访问共享内存中的地址。
3>共享内存的原理:在linux中,每个进程都有属于自己的进程控制块和地址空间,并且都有一个与之对应的页表,负责将进程的虚拟地址与物理地址进行映射,通过内存管理单元进行管理。两个不同的虚拟地址通过页表映射带物理空间的同一区域,他们所指向的这块区域即为共享内存。
4>共享内存接口函数及指令
1)查看系统中的共享存储段 命令: ipcs -m
2)删除系统中的共享存储段 命令:ipcrm -m [shmid]
3)shmget()创建共享内存
int shmget(key_t key, size_t size, int shmflg);参1:key:由ftok生成的key标识,标识系统的唯一IPC资源参2:size:需要申请共享内存的大小参3:shmflg:访问权限(和文件权限一致)如果是共享内存不存在,则需要使用IPC_CREAT或IPC_EXCL创建共享内存,如果是共享内存已经存在,可以使用IPC_CREAT或直接传0,获得共享内存返回值:成功返回一个新建或已经存在的的共享内存标识符,取决于shmflg的参数失败返回-1
4)shmat()挂接共享内存
void *shmat(int shmid, const void *shmaddr, int shmflg);参1:shmid: 共享存储段的标识符参2:shmaddr: shmaddr=NULL,则存储段连接到由内核选择的第一个可以地址上(推荐使用)参3:shmflg; 若指定SHM_RDONLY位,则以只读方式连接此段,0是以读写方式连接此段返回值:成功返回共享存储段的指针(虚拟地址)失败返回-1
5) shmdt()去关联共享内存
当一个进程不需要共享内存的时候,就需要去关联。该函数并不删除所指定的共享内存区,
而是将之前 用shmat
函数连接好的共享内存区脱离目前的进程。
6) shmctl()
销毁共享内存
int shmctl ( int shmid , int cmd , struct shmid_ds * buf );参 1 : shmid : 共享存储段标识符参 2 : cmd : 指定的执行操作,设置为 IPC_RMID 时表示可以删除共享内存参 3 : buf : 设置为 NULL 即可返回值:成功返回0失败返回 - 1
2.进程组和会话
1>概念和特性
每一个进程组有一个领头进程,进程组是一个或多个进程的集合,通常他们与一组作业相关联,可以接受来自同意终端的各种信号。每一个进程组都有位移的进程组ID。进程组由进程组ID来唯一标识。除进程号以外,进程组ID也是一个进程的必备属性之一。
PID = 进程ID (由内核根据延迟重用算法生成)
PPID = 父进程ID(只能由内核修改)
PGID = 进程组ID(子进程、父进程都能修改)
SID = 会话ID(进程自身可以修改,但有限制,详见下文)
TPGID= 控制终端进程组ID(由控制终端修改,用于指示当前前台进程组)
2)创建会话的6点注意事项
1. 调用进程不能是进程组组长,该进程变成新会话首进程 (session header)2. 该进程成为一个新进程组的组长进程。3. 需有 root 权限 (ubuntu 不需要 )4. 新会话丟弃原有的控制終端,该会话没有控制終端。5. 该调用进程是组长进程,则出错返回。6. 建立新会话时,先调用 fork, 父进程终止,子进程调用 setsidu
3)getsid()函数 : 获取进程所属的会话ID
pid_t getsid ( pid_t pid );返回值:成功 : 返回调用进程的会话 1D ;失败 : - 1 , 设置 errno参数:pid 为 0 表示查看当前进程 session ID
ps ajx命令:查看系统中的进程
![](https://i-blog.csdnimg.cn/blog_migrate/fd47f877e2f2b29c989a60be6e4b198f.png)
参数a 表示不仅列当前用户的进程,也列出所有其他用户的进程,参数x 表示不仅列有控制終端的进程,也列出所有无控制終端的进程,参数j 表示列出与作业控制相关的信息。小组长进程不能成为新会话首进程,新会话首进程必定会成为组 长进程。
4)stesid函数是创建一个会话,并以自己的ID设置进程组ID,同时也是新会话的ID。
pid_t setsid(void);返回值:成功: 返回调用进程的会话 ID;失败: -1. 设置 errno
调用setsid函数的进程,既是新的会长,也是新的组长。
3.系统守护进程介绍和创建
守护进程是一个在后台运行并且不受任何终端控制的进程。用于执行特定的系统任务。很多守护进程在系统引导的时候启动,并且一直运行直到系统关闭。另一些只在需要的时候才启动,完成任务后就自动结束。
1)创建守护进程的步骤
1.创建子进程,父进程退出。
所有工作在子进程中进行形式上脱离了控制终端。
2.在子进程中创建新会话
setsid()函数
是子进程完全独立出来,脱离控制。
3.改变当前目录(比如为根目录)
chdir()函数
防止占用可卸载的文件系统,也可以换成其他路径。
4.重设文件权限掩码
umask()函数
防止继承的的文件创建屏蔽于拒绝某些权限,增加守护进程灵活性。
5.关闭文件描述符
继承的打开文件不会用到,浪费系统资源,无法卸载。
6.开始执行守护进程核心工作守护进程退出处理程序模型
4.信号机制
1>信号在我们生活中随处可见,他们都有共性:简单、不能携带大量信息、满足某个特设条件才发送。
2)信号机制是一种使用信号来进行之前传递消息的方法,信号的全称为==软中断信号==,简称软中断。
信号的本质是软件层次上对中断的一种模拟(软中断)。它是一种异步通信的处理机制,事实上,
进程并不知道信号何时到来。
信号的特质:由于信号是通过软件方法实现,其实现手段导致信号有很强的延时性。但对于用户来说,这 个延迟时间非常短,不易察觉。
每个进程收到的所有信号,都是由内核负责产生和发送的,由内核处理。
信号是软件层面上的“中断
”
。一旦信号产生
,
无论程序执行到什么位置,必须立即停止运行,处理信号,
处理结束,再继续执行后续指令。
3) 与信号相关的事件和状态
产生信号:
1. 按键产生
2.系统调用产生。
3.软条件产生。
4.硬件异常产生
5.命令产生
递达 :递送并且到达进程,由内核处理掉
未决 :产生和递达之前的状态。主要由于阻塞导致该状态
信号的处理方式:
1.捕捉
2.忽略
3.按系统的默认值处理
阻塞信号集(信号屏蔽字):
将某些信号加入集合,对他们设置屏蔽(对应位设置为1),当屏蔽x信号后,
再收到该信号,该信号属 于未决信号集,直到解除屏蔽后才能处理。
未决信号集:
1.动作:信号产生后,未决信号集中描述该信号的位立刻翻转为1,表信号处
于未决状态。当信号被处理对应位翻转回为0。这一时刻往往非常短暂。
2.信号产生后由于某些原因(主要是阻塞)不能抵达。这类信号的集合称之为未
决信号集。在屏蔽解除前,信号一直处于未决状态。
![](https://i-blog.csdnimg.cn/blog_migrate/8d93024e91bd1fe3588ae7d6af92c628.png)
查看所有信号 ===>使用命令:kill -l
4)信号的四要素
1.编号 2.名称 3.事件 4.默认处理动作
5.信号的产生
1)终端按键产生信号
Ctrl+c→ 2) SIGINT ( 终止 / 中断 ) "INT" --interruptCtrl+z→ 20) SIGTSTP ( 暂停 / 停止 ) "T" --terminal 终端Ctrl+\→ 3) SIGQUIT ( 退出 )
2)硬件异常产生的信号
3)kill函数、命令产生信号
kill命令产生信号 : kill 所要杀的进程 pid 信号名称kill函数 : 给指定进程发送指定信号 ( 不一定杀死 ) 。int kill(pid_t pid, int sig)返回值:成功: 0;失败: -1 (ID非法,信号非法,普通用户杀 init 进程等权级问题 ) ,设置 errno.
普通用户基本规则是
:发送者实际或有效用户ID==接收者实际或有效用户ID。
4)软件产生信号
alarm函数:设置定时器(闹钟)。在指定seconds后,内核会给当前进程发送信号。进程收到该信号,默认动作终止。
每个进程都有且只有唯一一个定时器
取消定时器:alarm(0)
优化瓶颈:
使用time命令查看程序执行的时间。
程序运行的瓶颈在于IO,优化程序,首选优化IO
。
实际执行时间 = 系统时间 +
用户时间
+
等待时间。