您的位置:首页 > 其它

【2016/1】 Unix IPC 信号 共享内存 消息队列

2016-03-19 22:52 190 查看

Unix下的IPC

IPC样例 - github

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: