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

可以将简单地将信号灯想象成一个计数器,初始时计数器值为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. zoj 2949 - Coins of Luck

    题目:有2中面条各n碗.每次抛硬币推断吃哪一种(到一种吃完为止).问抛硬币的数学期望. 分析:动态规划.概率dp.求出每种结束状态(即,有一种吃完)的概率,分别乘以步长即为期望. 大黄解法:状态位剩余 ...

  2. LVS-DR,real-server为windows 2008的配置

    LVS-DR,real-server为windows 2008的配置 部署邮件系统负载均衡,采用LVS-DR模式,调度器是一台centos 5.8,real-server是两台windows2008, ...

  3. Lua学习七----------Lua函数

    © 版权声明:本文为博主原创文章,转载请注明出处 1.Lua函数 - 完成指定的任务,这种情况下函数作为调用语句使用 - 计算并返回值,这种情况下函数作为赋值语句的表达式使用 - Lua函数可以返回多 ...

  4. 数据库sql的join多表

    摘录文章 SQL join 用于根据两个或多个表中的列之间的关系,从这些表中查询数据.注意,join后的数据记录数不一定就是左或右表的简单连接,图表只代表集合关系,在数量上并不准确,如这个条件后结果, ...

  5. CSS3 实现背景透明,文字不透明,兼容所有浏览器

    <!DOCTYPE html><html><head><meta charset="utf-8"><title>opac ...

  6. Verilog代码规范(持续更新)

    1.输入输出的定义,看起来整齐 2.always.if或其他语句后begin写在同一行,这样可以避免begin占用过多的行,代码密度更大 3.end后面要有注释,以标明是哪个关键词的结束,除了endc ...

  7. mysql解决中文乱码

    mysql>use mydb; mysql>alter database mydb  character set utf8;! 这种方法只对设置后重新创建的表有效,对已存在的表无效 des ...

  8. HDFS源码分析心跳汇报之数据块汇报

    在<HDFS源码分析心跳汇报之数据块增量汇报>一文中,我们详细介绍了数据块增量汇报的内容,了解到它是时间间隔更长的正常数据块汇报周期内一个smaller的数据块汇报,它负责将DataNod ...

  9. C#之stream

    在C#中经常要用stream stream下面主要有 FileStream:使用文件作为后备设备. BufferedStream:使用缓冲区作为后备设备,用来增强性能的中间存储. MemoryStre ...

  10. 【SSH进阶之路】Hibernate映射——一对一单向关联映射(五)

    [SSH进阶之路]Hibernate基本原理(一) ,小编介绍了Hibernate的基本原理以及它的核心,採用对象化的思维操作关系型数据库. [SSH进阶之路]Hibernate搭建开发环境+简单实例 ...