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

可以将简单地将信号灯想象成一个计数器,初始时计数器值为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. 修改Oracle SGA,以提高oracle性能

    在正常情况下,查询非常慢. 1.检查SGA大小,以DBA身份连接到oracle数据库,输入show sga. 2.如果SGA过小,请修改其大小 修改SGA必须保持的原则 1).sga_target不能 ...

  2. keras----resnet-vgg-xception-inception

    来源: https://www.pyimagesearch.com/2017/03/20/imagenet-vggnet-resnet-inception-xception-keras/ classi ...

  3. linearLayout 和 relativeLayout的属性区别

    LinearLayout和RelativeLayout 共有属性: java代码中通过btn1关联次控件 android:id="@+id/btn1" 控件宽度 android:l ...

  4. 图像检测之sift and surf---sift中的DOG图 surf hessian

    http://www.cnblogs.com/tornadomeet/archive/2012/08/17/2644903.html http://www.cnblogs.com/slysky/arc ...

  5. webstorm vscode 常用设置

    webstorm常用的设置及操作图解 VS Code 新建vue文件初始化模板 VSCode新建vue文件自定义模板

  6. SSIS

    http://www.cnblogs.com/codefish/category/557802.html

  7. 九度OJ 1056:最大公约数 (GCD)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:6278 解决:4075 题目描述: 输入两个正整数,求其最大公约数. 输入: 测试数据有多组,每组输入两个正整数. 输出: 对于每组输入,请 ...

  8. wepy 实现 用户名登录与短信验证码登录

    wepy 实现 用户名登录与短信验证码登录

  9. Spanner: Google’s Globally-Distributed Database

    https://research.google.com/archive/spanner.html Spanner is Google’s scalable, multi-version, global ...

  10. ideal 快捷键

    1.输入sout --> System.out.println(); 2.输入psvm --> main函数; IntelliJ Idea 2017 免费激活方法 1. 到网站 http: ...