四、信号
4.1 信号综述
信号就是软中断,相关定义在头文件<signal.h>中,信号名被定义为正整数常量。
信号的响应分为三种:
1)忽略此信号。SIGKILL和SIGSTOP不能忽略
2)捕捉信号
3)执行系统默认动作,通常是终止该进程,有的是终止+core
UNIX系统定义了约45种信号
4.2 signal
自己定义信号以及处理函数
void (*signal(int, void(* func)(int)))(int);
这里,注意signal是一个函数,而不是函数指针,它返回值是一个函数指针,并且参数有一个也是函数指针
等同于:
typedef void Sigfunc(int);
Sigfunc * signal(int, Sigfunc *)
func的值除了函数地址,还可以是SIG_IGN, SIG_DFL.表示忽略和默认处理此信号。
调用fork的子进程,由于复制了父进程的内存映像,因此继承父进程的信号处理方式
4.3 可重入函数
SUS说明了可重入函数(又称异步信号安全),即不会因为执行信号处理而改变信号来临前函数的正常工作状态。
SUS说明了信号处理程序中保证调用安全的函数,具体可见图10-4。不可重入函数:a)使用静态数据结构;b)调用malloc或free;c)调用标准I/O函数。
4.4 kill和raise, alarm和pause
kill函数将信号发送给进程或进程组,raise函数则允许进程向自身发送信号
alarm设置一个定时器,超时产生SIGALRM信号。pause则使调用进程挂起直到捕捉到一个信号。
4.5 信号集与信号屏蔽字
signal set数据结构:sigset_t。
sigprocmask函数:检测或更改进程的信号屏蔽字。
sigpending函数:返回一个信号集,各信号是阻塞不能迭代的。
4.6 其他函数
abort函数发出SIGABRT信号给调用进程
system函数可以执行传入字符串的命令
sleep函数:墙上时间经过n秒
五、线程
5.1 多线程的好处
1)每种类型事件抽象为一个线程,然后可以用同步编程模式代替异步
2)比多进程更容方便实现内存和文件描述符的共享
单个线程拥有的资源:
线程ID,一组寄存器值,栈,调度优先级和策略,信号屏蔽字,errno变量以及线程私有数据
5.2 线程相关的一堆函数
由于之前的一个测试平台搭建项目,很多接口已经比较熟悉了,这里只做一下罗列:
pthead_create, pthread_equal,pthread_self, pthread_exit, pthread_join, pthread_cancel, pthread_cleanup_push, pthread_cleanup_pop, pthread_detach
pthread_join从控制流中得到退出状态,但是pthread_detach分离线程之后,线程的底层存储资源在线程终止时被立即收回,而不能再用pthread_join。
5.3 线程同步
当多个线程读写交错的时候,就要考虑线程同步问题。由于内存地址空间和文件描述符都是共享的,因此相比进程,要格外注意同步问题。
这里罗列一下POSIX的各种同步机制
a)互斥量
pthread_mutex_init, pthread_mutex_destroy,
pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock,pthread_mutex_timedlock
注意避免思索:加锁的顺序要一致
b)读写锁
读共享,写排他
一次只有一个县城可以占有写模式的读写锁,但是多个线程可以同时占有读模式的读写锁
c)条件变量
条件本身是由互斥量保护的,线程在改变条件状态之前必须首先锁住互斥量。
pthread_cond_init,pthread_cod_destroy,
pthread_cond_wait, pthread_cond_timedwait
pthread_cond_signal, pthread_cod_broadcast
d)自旋锁
自旋锁与互斥量类似,但它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等(自旋)阻塞状态。自旋锁的适用场景:锁被持有的时间短,而且线程不希望在重新调度上花费太多成本
pthread_spin_init, pthread_spin_destory
pthread_spin_lock, pthread_spin_trylock, pthread_spin_unlock
e)屏障
barrier允许每个线程等待,直到所有的合作线程都达到某一点,然后从该点继续执行。pthread_join也是一种屏障,允许一个线程等待,直到另一个线程退出
pthread_barrier_init, pthread_barrier_destroy
pthread_barrier_destroy, pthread_barrier_wait
5.4 线程限制
sysconf可以读出系统对线程的限制:
PTHREAD_KEYS_MAX
PTHREAD_STACK_MIN
PTHREAD_THREADS_MAX
5.5 线程属性与同步属性
pthread_attr_init, pthread_attr_destroy
pthread_attr_getdetachstate, pthread_attr_setdetachstate
与线程对象一样,线程的同步对象也有属性。并且提供相应接口,不列举了。
5.6 重入问题
线程安全与异步信号安全是两个不同的概念!!!
SUS列出了线程不安全的函数,见P355图12-9。
5.7 线程特定数据
也称为线程私有数据。
由于线程ID不是小而连续的证书,所以不能简单地分配一个用线程ID作索引的每线程数据数组。还有一个需要考虑的问题是我们希望提供一些额外的保护机制。
UNIX的设计是:在分配线程特定数据之前,需要创建与该数据关联的键,这个键将用于特定数据的访问。相关接口:
pthread_key_create, pthread_key_delete, pthread_once
六、 IPC
进程间数据交换,文件,IPC,Socket,UNIX域套接字
其实这几种都应该算是IPC方式。
6.1 UNIX IPC
包括pipe,FIFO,消息队列,信号量,共享存储
6.1.1 pipe
管道是UINIX最古老的IPC形式。要注意,FIFO又称为命名管道,而UNIX域套接字有时称为fd管道。
PIPE的局限性如下:
1)为了可移植性,最好只用半双工。
2)管道只能在具有公共祖先的两个进程之间使用。通常,一个管道由一个进程创建,在进程调用fork之后,这个管道就能在父子进程之间使用了。
命名管道不受第二个限制,FD管道两个限制都没有。
每一次shell执行一个命令序列时,shell会为每一条命令单独创建一个进程,然后用管道将前一条命令进程的标准输出与后一条命令进程的标准输入相连。
popen与pclose两个函数要注意。
popen封装了常见的pipe操作:创建一个管道,fork一个子进程,关闭未使用的管道端,执行一个shell运行命令,然后等待命令终止。
6.1.2 FIFO
FIFO是一种文件类型,可以适用文件的那套统一接口。FIFO也有路径名。创建接口:mkfifo, mkfifoat
6.1.3 XSI IPC
XSI IPC都有一个标识符,并且需要制定一个key。每一个IPC对象与key绑定。
消息队列:msgget, msgsnd, msgrcv, msgctl
信号量:semget, semop, semctl
共享存储:shmget, shmctl, shmat, shmdt
6.1.3 POSIX信号量
SUSv4,POSIX信号量被移入标准,消息队列和共享内存则没有。
注意与XSI 信号量区别:
sem_open, em_close, sem_unlink, sem_trywait, sem_wait, sem_timedwait, sem_post, sem_init, sem_destroy, sem_getvalue
6.2 网络IPC:套接字
额,这部分内容,我会在UNIX网络那本书的笔记中,再详细记录,由于这个用得也必将多,所以直接摆摆函数,记录下吧
socket, shutdown, bind, connect, listen, accept, send, sendmsg, rec, recvfrom, recvmsg, setsockopt
注意shutdown与close的区别,
accept传入socked,返回new sockfd connected to client
6.3 UNIX域套接字
socket可以有不同的域,UNIX域就是其中的一种
socketpair来创建一对无命名的、相互连接的UNIX域套接字
建立连接:serv_listen, serv_accept, cli_con
额,没有时间了,发布了,不想拖到2017年。。
2016年就这样结束了,祝自己和家人明年平安,好运!