信号灯(信号量)不是进程通信手段,其是用于控制和协调在进程间通信过程中的共享资源访问,就如同互斥锁(两者的区别可以参考这里) 

可以将简单地将信号灯想象成一个计数器,初始时计数器值为n(有n个资源可供使用),当进程占用资源时计数器减1,资源被释放时计数器加1,没有资源可用时计数器为0。 

如果资源只用“可用/不可用”这样的非是即否的状态的话,信号灯称为二值信号灯(binary semaphre),相反地,称为计数信号灯(counting semaphores) 

将信号灯的原理表示成代码的话,则非常简单: 

//假设s为信号灯
//等待信号灯
wait(s)
while (s<=)
{
//do nothing
}
//等到了,那么我要使用了哦
s=s-;
//使用中
P(s)
//我使用完毕了
s=s+; 与共享内存一样,信号量也分为System V和POSIX两种,这里看看System V的。 新建信号量集: int semget(key_t key, int nsems, int semflg);
key参数和smflg参数与shmget一样
nsems参数:表示该信号量集中的信号量个数。一个信号量集中可以包含多个信号量,所能包含的最大数量由SEMMSL宏决定。
与之相关联的数据结构的是:
struct semid_ds {
struct ipc_perm sem_perm; /* permissions .. see ipc.h */
__kernel_time_t sem_otime; /* last semop time */
__kernel_time_t sem_ctime; /* last change time */
struct sem *sem_base; /* ptr to first semaphore in array */
struct sem_queue *sem_pending; /* pending operations to be processed */
struct sem_queue **sem_pending_last; /* last pending operation */
struct sem_undo *undo; /* undo requests on this array */
unsigned short sem_nsems; /* no. of semaphores in array */
}; 其中的sem_nsems字段便是信号集中的信号数量。 用semctl进行一些和设置以及取得信号量的一些属性信息 int semctl(int semid, int semnum, int cmd, ...); semid参数: 信号量集对应的id semnum参数: 本次操作所针对的信号在信号集中的序号 cmd参数: 所进行的操作,这里的操作有很多种,比如IPC_STAT是用于获取信号的属性信息,SETVAL用于设置信号量的值,具体的参考这里 可变参数(…): 可变参数取决去前面的cmd参数,但一般是由如下联合构成的: union semun { int val; struct semid_ds *buf; ushort *array; } arg; 比如cmd为SETVAL时,semun则被解释为int val,用于设置信号量的值: arg.val = ; semctl(semid,,SETVAL,arg) //将semid对应的信号集中的索引为0的信号的值设置为1 当cmd为IPC_STAT时,则semun被解释为struct semid_ds* buf,相关信息被复制到buf中 我们用semop函数来操作一个或一组信号量,并保证操作的原子性(当操作几个信号时,要么全部成功,要么全部失败) int semop(int semid, struct sembuf *sops, unsigned nsops); sops参数: 为了便于理解,你可以将struct sembuf *sops 参数想象成 struct sembuf sops_array[],其是一个数组,数组中的每一个元素将针对信号量集中的一个信号量进行操作,所以这个操作数组便可以用于表示对多个信号量进行操作。 struct sembuf结构中包含了要进行的操作的相关信息: struct sembuf { ushort sem_num; /*操作针对信号集中的哪个信号 */ short sem_op; /*操作 */ short sem_flg; /*一些flag: IPC_NOWAIT ,SEM_UNDO*/ }; 关于sem_op操作: )如果其值为正数,该值会加到现有的信号内含值中。通常用于释放所控资源的使用权; )如果sem_op的值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。通常用于获取资源的使用权; )如果sem_op的值为0,则操作将暂时阻塞,直到信号的值变为0。 关于sem_flg标记: )IPC_NOWAIT 对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息。 )SEM_UNDO 程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。 nsops参数: sops数组的元素个数。 下面有一个小DEMO: #include <stdio.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h> void main()
{
key_t unique_key; /* 定义一个IPC 关键字*/
int id;
struct sembuf lock_it;
union semun options;
int i; unique_key = ftok(".", 'a'); /* 生成关键字,字符'a'是一个随机种子*/ /* 创建一个新的信号量集合*/
id = semget(unique_key, , IPC_CREAT | IPC_EXCL | );
printf("semaphore id=%d\n", id);
options.val = ; /*设置变量值*/
semctl(id, , SETVAL, options); /*设置索引0 的信号量*/ /*打印出信号量的值*/
i = semctl(id, , GETVAL, );
printf("value of semaphore at index 0 is %d\n", i); /*下面重新设置信号量*/
lock_it.sem_num = ; /*设置哪个信号量*/
lock_it.sem_op = -; /*定义操作*/
lock_it.sem_flg = IPC_NOWAIT; /*操作方式*/ if (semop(id, &lock_it, ) == -)
{
printf("can not lock semaphore.\n");
exit();
} i = semctl(id, , GETVAL, );
printf("value of semaphore at index 0 is %d\n", i); /*清除信号量*/
semctl(id, , IPC_RMID, );
} 注,信号量和互斥锁的区别

linux 进程学习笔记-信号semaphore的更多相关文章

  1. linux 进程学习笔记-进程信号sigal

    信号(或软中断)是在软件层次上对中断的一个模拟,其运行在“用户空间”,一个进程对另外一个或几个进程通过发送信号来实现异步通信.当接收进程接收到信号后,其可以注册一下处理函数来说对这些信号进行处理(也可 ...

  2. Linux 进程学习笔记

    1.什么是程序?什么是进程?它们有什么区别? 定义: 程序:程序(Program)是一个静态的命令集合,程序一般放在磁盘中,然后通过用户的执行来触发.触发后程序会加载到内存中成为一个个体,就是进程. ...

  3. linux 进程学习笔记-暂停进程

    <!--[if !supportLists]-->Ÿ <!--[endif]-->暂停进程 int pause() 其会挂起当前进程直到有信号来唤醒或者进程被结束. 随便提一下 ...

  4. linux 进程学习笔记-消息队列messagequeue

    可以想象,如果两个进程都可以访问同一个队列:其中一个进程(sender)向其中写入结构化数据,另外一个进程(receiver)再从其中把结构化的数据读取出来.那么这两个进程就是在利用这个队列进行通信了 ...

  5. linux进程学习笔记

    学习了linux下的进程,觉得应该整理一下,忘得差不多了,顺便回顾一下. 学而时习之,不亦说乎~~ 进程笔记 ,什么是进程? The Single UNIX Specification, Versio ...

  6. linux 进程学习笔记-进程跟踪

    进程跟踪 long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data); Linux用ptrace来进行进 ...

  7. linux 进程学习笔记-进程ID,PID

    PID,进程号 , 范围在2~(??为什么需要这么多),而一个名为idle (或swapper)的进程占据的编号0,init进程占据了编号1. 进程0和进程1 : 系统启动时会从无到有地创建进程0,它 ...

  8. linux 进程学习笔记-进程调度

    在分时系统中,系统将CPU时间划分成无数个时间片(quantum)分配给不同的进程,一个时间片只执行一个进程,并且不停地切换,以让用户感觉到各个进程是在“同时运行”,这中间所需要的策略和算法便是进程调 ...

  9. linux 进程学习笔记-进程状态

    task_struct的state字段记录的进程的状态,可分为如下几种: #define TASK_RUNNING 0 可运行状态.这是 “进程正在被CPU运行” 和 “进程正在可运行队列中等待被CP ...

随机推荐

  1. SQL CASE WHEN ... THEN ... ELSE.. END 实例

    用一个SQL语句完成不同条件的分组(SELECT部分): select QuoteOrderId,SUM(case when(ApprovalStatus=1)then Amount else 0 e ...

  2. Orcad CIS怎么批量修改字体大小

    选中DSN,右键,design properties, schematic design,选择design properties.

  3. hdu 1203 I NEED A OFFER!(01背包)

    题意:"至少一份offer的最大概率".即求拿不到offer的最小概率 (得到offer的最大概率 = 1 - 反例的最小概率). 状态转移方程:dp[j]= Min(dp[j], ...

  4. Ajax请求的跨域(CORS)问题

    用浏览器,通过XHR(XMLHttpRequest)请求向另外一个域名请求数据时.会碰到跨域(CORS)问题. CORS:Cross-Origin Resource Sharing 什么是跨域? 简单 ...

  5. Django--网页管理实例解析

    此篇为代码流程的注释以及自己写的小项目的思路: 首先是项目的路由配置: urlpatterns = [ # url(r'^admin/', admin.site.urls), url(r'^yemia ...

  6. js高度line-height及宽度text-align:center居中插件

    1.高度居中---在高度设为100%,无法直接使用line-height:100%;会不起效果 这是用于应对height:100%的插件 /** * 高度居中函数,用于应对高度设为100%时的居中 * ...

  7. js 第一篇(常用交互方法)

    1. cocument.write("content") //向html 直接写入内容 2. alert("content") // 警告对话框 3. conf ...

  8. typeof 与 instanceof 区别

    typeof typeof 是一元运算符,返回值是字符串,且只能是number,string,boolean,object,function,undefined typeof用来判断一个值是否存在 i ...

  9. Oracle -- Create User

    CREATE USER hibernate IDENTIFIED BY "123" DEFAULT TABLESPACE "HIBERNATE" TEMPORA ...

  10. PowerBuilder -- 保存图片

    String ls_path, ls_file_name, ls_filter, ls_errInt li_ret, li_loop, li_i, li_file, li_bytesLong ll_f ...