linux的常用信号量
创新互联服务项目包括三明网站建设、三明网站制作、三明网页制作以及三明网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,三明网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到三明省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!
BUS与SEGV
二者都是错误信号,BUS表示总线错误,SEGV表示段错误,程序崩溃的时候99%都是这两个错误导
致的。进程可以捕获和封锁这两类错误。内核对二者的默认处理是memory dump
WINCH
窗口改变信号(WINdown CHanged)。例如虚拟终端的行数发生变化时将发送WINCH信号,绝大多数
文本编辑器都能捕获WINCH信号自动进行重新配置。内核的默认处理是忽略该信号,并且不进行内存
转储。
进程可以捕获或者封锁该信号
KILL
杀死/删除进程,编号为9
STOP
挂起/暂停正在执行的进程,直到收到CONT为止
KILL STOP都不能够被捕获、封锁或者忽略,默认处理都不会产生内存转储。
CONT
取消挂起,继续执行进程
TSTP
是STOP信号的“软”版本,即在用户输入Ctrl+Z时由终端驱动程序发送的信号。捕获到该信号的进程通常
清除它们的状态,如何给自己发送一个STOP信号。TSTP的默认处理不会导致内存转储。
INT
中断信号,编号为2
当用户输入Ctrl+C时由终端驱动程序发送INT信号
INT信号是终止当前操作的请求,简单程序捕获到INT信号时应该退出,拥有命令行或者输入模式的那些
程序应该停止他们正在做的事情,清除状态,并等待用户再次输入。
TERM
软件终止信号,编号为15
TERM是请求彻底终止某项操作的信号,它期望进程清楚自己的状态并退出
QUIT
退出信号,编号为3
与TERM类似,不同之处在于QUIT信号的默认处理是内存转储,而TERM信号的默认处理没有内存转储。
HUP
挂起信号,编号为1,有两种解释:
守护进程理解HUP为重新设置的请求,如果守护进程能够不用重新启动就能够重新读取它自己的配置文
件并调整自己以适应变化的话,那么HUP信号通常可以用来触发这种行为
HUP
信号有时有终端驱动程序生成,试图用来清除(也就是终止)跟某个特定终端相连接的那些进程。例如
当一个终端会话结束时,或者当一个Modem的连接不经意的断开时,就可能出现这种情况。
如果需要某些进程在会话结束之后继续运行,那么在C Shell中设法让这些进程变成后台程序,
ksh或者bash中可以用nohup来模拟这种行为。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
进程的四种状态
runnable(可运行状态)
只要有CPU时间,进程就可以执行。一旦进程执行了不能立即完成的系统调用,Linux会把进程转入
睡眠状态
sleeping(睡眠状态)
进程在等待某些事件发生(如终端输入、网络连接)
zombie(僵化状态)
进程已经执行完毕并试图消亡,但是状态没有收集完
stopped(停止状态)
进程被挂起,不允许执行。进程收到STOP或者TSTP信号即进入停止状态,可以用CONT信号来重新启动
Linux信号量(semaphore)是一种互斥机制。即对某个互斥资源的访问会收到信号量的保护,在访问之前需要获得信号量。
在操作完共享资源后,需释放信号量,以便另外的进程来获得资源。获得和释放应该成对出现。
获得信号量集,需要注意的是,获得的是一个集合,而不是一个单一的信号量。
#include
#include
#include
1: int semget(key_t key,int nsems,int semflg);
key:系统根据这个值来获取信号量集。
nsems:此信号集包括几个信号量。
semflg:创建此信号量的属性。 (IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)
成功则返回该信号量集的ID。
注:
既指定IPC_CREAT又指定IPC_EXCL时,如果系统中该信号量集已经存在,则马上返回。
如果需要获得存在的信号量,则将此参数置0.
2: int semctl(int semid,int senum,int cmd....)
semid:信号量ID。
senum:对信号量集中的第几个信号量进行控制。(从0开始)
cmd:需要进行的操作。(SETVAL是其中的一个)。
根据cmd的不同可能存在第四个参数,cmd=SETVAL时,表示同时信号量可以被获得几次,如第四个参数
num=1表示只能被获得一次,既被信号量保护的资源只能同时被一个程序使用。
该系统调用,是在对信号量初始化时用的。
-3: “3”前面加了"-"表示当需要使用互斥资源时应该做这步。
int semop(int semid,struct sembuf *sem,int num_elements);
struct sembuf {
unsigned short sem_num; //该信号量集中的第几个信号量。
int sem_op;//需要获得还是释放信号量
int sem_flg;//相关动作
};
num_elements:需要对该信号量集中的多少个信号量进行处理。
获得信号量时,将sembuf结构提初始化为:
sem_num = 0; //该信号量集中的首个信号量
sem_op = -1; //获得信号量
sem_flag = IPC_NOWAIT; //如果不能获得信号量,马上返回。
semop(semid,_sem,1);
同理释放信号量时,将sem_op设为1.
以上是对信号量的简单处理
信号量是包含一个非负整数型的变量,并且带有两个原子操作wait和signal。Wait还可以被称为down、P或lock,signal还可以被称为up、V、unlock或post。在UNIX的API中(POSIX标准)用的是wait和post。
对于wait操作,如果信号量的非负整形变量S大于0,wait就将其减1,如果S等于0,wait就将调用线程阻塞;对于post操作,如果有线程在信号量上阻塞(此时S等于0),post就会解除对某个等待线程的阻塞,使其从wait中返回,如果没有线程阻塞在信号量上,post就将S加1.
由此可见,S可以被理解为一种资源的数量,信号量即是通过控制这种资源的分配来实现互斥和同步的。如果把S设为1,那么信号量即可使多线程并发运行。另外,信号量不仅允许使用者申请和释放资源,而且还允许使用者创造资源,这就赋予了信号量实现同步的功能。可见信号量的功能要比互斥量丰富许多。
POSIX信号量是一个sem_t类型的变量,但POSIX有两种信号量的实现机制: 无名信号量 和 命名信号量 。无名信号量只可以在共享内存的情况下,比如实现进程中各个线程之间的互斥和同步,因此无名信号量也被称作基于内存的信号量;命名信号量通常用于不共享内存的情况下,比如进程间通信。
同时,在创建信号量时,根据信号量取值的不同,POSIX信号量还可以分为:
下面是POSIX信号量函数接口:
信号量的函数都以sem_开头,线程中使用的基本信号函数有4个,他们都声明在头文件semaphore.h中,该头文件定义了用于信号量操作的sem_t类型:
【sem_init函数】:
该函数用于创建信号量,原型如下:
该函数初始化由sem指向的信号对象,设置它的共享选项,并给它一个初始的整数值。pshared控制信号量的类型,如果其值为0,就表示信号量是当前进程的局部信号量,否则信号量就可以在多个进程间共享,value为sem的初始值。
该函数调用成功返回0,失败返回-1。
【sem_destroy函数】:
该函数用于对用完的信号量进行清理,其原型如下:
成功返回0,失败返回-1。
【sem_wait函数】:
该函数用于以原子操作的方式将信号量的值减1。原子操作就是,如果两个线程企图同时给一个信号量加1或减1,它们之间不会互相干扰。其原型如下:
sem指向的对象是sem_init调用初始化的信号量。调用成功返回0,失败返回-1。
sem_trywait()则是sem_wait()的非阻塞版本,当条件不满足时(信号量为0时),该函数直接返回EAGAIN错误而不会阻塞等待。
sem_timedwait()功能与sem_wait()类似,只是在指定的abs_timeout时间内等待,超过时间则直接返回ETIMEDOUT错误。
【sem_post函数】:
该函数用于以原子操作的方式将信号量的值加1,其原型如下:
与sem_wait一样,sem指向的对象是由sem_init调用初始化的信号量。调用成功时返回0,失败返回-1。
【sem_getvalue函数】:
该函数返回当前信号量的值,通过restrict输出参数返回。如果当前信号量已经上锁(即同步对象不可用),那么返回值为0,或为负数,其绝对值就是等待该信号量解锁的线程数。
【实例1】:
【实例2】:
之所以称为命名信号量,是因为它有一个名字、一个用户ID、一个组ID和权限。这些是提供给不共享内存的那些进程使用命名信号量的接口。命名信号量的名字是一个遵守路径名构造规则的字符串。
【sem_open函数】:
该函数用于创建或打开一个命名信号量,其原型如下:
参数name是一个标识信号量的字符串。参数oflag用来确定是创建信号量还是连接已有的信号量。
oflag的参数可以为0,O_CREAT或O_EXCL:如果为0,表示打开一个已存在的信号量;如果为O_CREAT,表示如果信号量不存在就创建一个信号量,如果存在则打开被返回,此时mode和value都需要指定;如果为O_CREAT|O_EXCL,表示如果信号量存在则返回错误。
mode参数用于创建信号量时指定信号量的权限位,和open函数一样,包括:S_IRUSR、S_IWUSR、S_IRGRP、S_IWGRP、S_IROTH、S_IWOTH。
value表示创建信号量时,信号量的初始值。
【sem_close函数】:
该函数用于关闭命名信号量:
单个程序可以用sem_close函数关闭命名信号量,但是这样做并不能将信号量从系统中删除,因为命名信号量在单个程序执行之外是具有持久性的。当进程调用_exit、exit、exec或从main返回时,进程打开的命名信号量同样会被关闭。
【sem_unlink函数】:
sem_unlink函数用于在所有进程关闭了命名信号量之后,将信号量从系统中删除:
【信号量操作函数】:
与无名信号量一样,操作信号量的函数如下:
命名信号量是随内核持续的。当命名信号量创建后,即使当前没有进程打开某个信号量,它的值依然保持,直到内核重新自举或调用sem_unlink()删除该信号量。
无名信号量的持续性要根据信号量在内存中的位置确定:
很多时候信号量、互斥量和条件变量都可以在某种应用中使用,那这三者的差异有哪些呢?下面列出了这三者之间的差异: