Unix下的IPC
kill -l #查看所有信号
kill 不加signum的时候默认发送15号信号
原子操作: 防止被中断的操作 kill -9 使用的就是这个操作且不可被更改
15号信号是可以被终结的9号信号
除了9与19号信号, 别的信号的操作内容都是可以修改的
ctrl + c : 2号信号 SIGINT
— 用^c关闭不掉的进程就是被1号进程接管了,或者为了保护它就放在后台
1.信号
signal()来注册自己编写的信号处理(handler)
— 很多信号的默认操作都是退出
信号最终是由内核中转发送给进程的
— 信号是不可靠的, 是可以被屏蔽的(未决性) 无法保证完全的实时性
— 信号屏蔽时并未消失 只是被延迟了
sigset_t 信号屏蔽字 64位代表64个接受或者不接受的状态
— 对屏蔽字的操作在signal.h中封装了
— 制作好屏蔽字后要用sigprocmask来将其适用
调用abort()函数可以给自己发送一个SIGABRT信号
同时这个信号也会被多次free触发
调用pause()函数进入无限期睡眠, 直到收到一个信号时才被唤醒
调用alarm()函数 在传入参数的时间到时 发送一个SIGALRM信号
时间编程:
clock_nanosleep()一个高精度的表 如果被打断 还会记录剩余的时间
— 配合sleep() 防止sleep没有到达预定的挂起时间 还有usleep()
可以用gettimeofday()的毫秒时间作为随机数,得到1979到现在秒数
— 更精确的的clock_gettime()
— 系统时间的精度有两个结构体 timespec 纳秒级别 timeval 微秒级别
— localtime(从1970到现在的秒数) 格式化输出年月日时间 输出tm结构体
系统级别就是/etc/rc.d下的脚本,用init几就是运行哪个目录下的服务
** 操作系统启动过程!
《Unix服务器编程》
《操作系统原理》《现代操作系统》
sigpending() 在屏蔽时间 获取期间到达的信号(阻塞状态)
— 获取信号的同时不用被打断 而是用自己的方式处理
sigsetjmp() 可以进行goto式的跳跃,但是不建议使用
为何goto不能在函数间跳转:
内存空间的冲突,栈内存,代码段内存等,关键字操作在编译阶段,
不能控制指令运行时候的内存分配,只能用系统或者函数调用
SIGCHID 子进程终止时给父进程发的信号
sigsuspend() 临时替换当前进程的信号屏蔽字 会挂起一直到有信号到达
— 等待的是传入的屏蔽字中屏蔽的信号以外的信号到达才会终止
raise(sig) 给自己发一个信号 等同于 kill(getpid(), sig)
sigqueue() 加强版的kill函数 用位操作来制作sigval来传入参数
sigaction() 注册信号 同时保存之前的信号操作到一个结构体中
— 结构体中有操作方法的函数指针 同时还存着另一种操作方法
— 另一种操作方法中带有一个包含很多信息的结构体(siginfo_t)
**tips:
如果用exec之前创建了屏蔽字并且应用了
那么用exec之后 即使进程空间被替换 进程的控制信息依然保留
所以原来程序对信号的控制依然存在
— 信号管控服务!
进程间通信:
Linux下的IPC ipcs可以查看进程共享的内存段
文件系统 效率较低
信号 用信号传递小的信息
2.管道
管道 pipe()-只基于内存 非衍生进程都不能看到
— 管道中的数据是一次性的 传递完信息就没有了
0 号成员来读 1 号成员来写
父子进程会复制描述符 但是描述符继承的是同一条管道
— 描述符指向的空间是共享的
用一条管道传输多个进程的内容:
约定内容长度,让子进程只接受一个长度的内容
管道最大的容量:4096
管道读完了默认挂起而不是
fd的控制: fcntl()
gbd调试: gdb attach <进程号>
bt: (back trace)查看其中进程的栈针(运行的位置)
detach: 礼貌性的退出
unlimit -c unlimited 解开core dump 的限制
然后把core.文件用gdb阅读
unlimit -c 0 关闭core file的系统
int mkfifo(const char *pathname, mode_t mode);
制作一个有名管道 使用管道依然要open
但是管道不能长期存储, 只有在进程运行时可以访问数据
3.共享内存
每个进程都可以使用的内存, 整个系统范围有效
内存具有key shmid
key=0 的共享内存表示私有内存 不想被别人使用
但通过shmid既然可以访问共享内存
共享内存是独立于进程的,只要不删除就一直存在
给别的进程对共享内存进行访问控制的方法
Usage:
shmget() 可以创建或者刷新获得一块内存 通过key与大小 返回是一个ID
shmat() 用返回的ID使用一块内存(映射) *单一进程有效! attach
shmdt() 不再使用内存 don’t attach
shmctl() 对共享内存进行控制信息的更改,获取或者修改
ipcrm -m shmid 删除by id
ipcrm -M key 删除by key
不建议用cmd删除shm,最好在代码中shmctl删除,排除异常情况
tips: 所有有意义的内存都需要初始化, 要么赋值 要么memset
制作程序显示共享内存的值 以16进制按行显示 第一列是内存地址
strtol() 转换任意进制
父进程在收到一个信号的时候 bash会给其下所有子进程发送相同的信号
2016-1-17:
cat /proc/sys/kernel/shm* 里面有有关共享内存的信息
4.消息队列:
消息只会一条条的收,分条发送和接受
**msgget()** 使用key值来得到消息 返回一个ID值 用来以后收发消息
**msgctl()** 得到控制信息来改变消息队列的信息(最好在创建消息队列之前)
— 先获取msg的控制信息 然后更改之后再存回去 否则可能是垃圾值
msgrcv() / msgsnd() 收发消息 原子操作:不会被另一个进程打断
— 发送的数据是一个结构体,结构体的首成员必须是一个long的标记值
— 消息的挂起: 发送的时候队列满了与接受的时候队列为空
— 消息的身份是由type决定的 当recv type为 0 时直接收队首的消息
— msgflag为MSG_EXCEPT 时是除了为type的第一条消息被收走
— type 为负值 收绝对值小与等与它的最小值
ls /proc/sys/kernel/msg* 中有msg的宏值与信息
更改内核的一些参数 再/etc/sysctl.conf 中添加参数:
eg: kernel.msgmnb = 2048
(把/proc/sys/中的内容的目录/改为点 然后就可以修改了)
sysctl -p 刷新内核参数文件
信号量是一个资源计数器
*互斥锁:资源计数为1(有人使用立即临界,不能被使用)
临界区 临界资源-> 某一时刻只能由一个程序接受的资源(键盘)
— 同时只能由一个程序来操作临界区的代码段的代码
semget() nsems参数为信号量级
semctl() 对于信号量进行操作,设定信号量初值等
— 在最开始初始化之后不要随便更改 否则影响互斥的能力
semop() / semtimedop() 信号操作 pv操作 +-1来加减锁
***tip: 了解一下PV操作
— 系统保护: 如果加锁的人不在了 系统自动解锁(UNDO)
— 实现了同步异步
Linux下 C语言基本类型(四字节及以下)的赋值是原子操作
Tips:
伙伴系统原理: 用N个链表来管理内存块 在申请内存时根据内存大小
轮询合理的内存位置 在把多余的空间分配到链表上
36-> 32 + 32 -> 32 + 4 + 16 + 8 + 4 -> 36 + 16 + 8 + 4
然后把16 8 4 放在限定内存大小为16 8 4 的内存链表上
释放的时候自动查询连续的空白内存块合并 防止内存不连续的问题
十八种内存管理系统技术 MMU