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

可以将简单地将信号灯想象成一个计数器,初始时计数器值为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. shell脚本实现定时重启任务并输出日志信息

    #!/bin/bash #当前日期 time=`date` pidno=`ps aux|grep adserver-beta|grep -v "grep"|awk '{print ...

  2. hdu 4862 KM算法 最小K路径覆盖的模型

    http://acm.hdu.edu.cn/showproblem.php?pid=4862 选t<=k次,t条路要经过全部的点一次而且只一次. 建图是问题: 我自己最初就把n*m 个点分别放入 ...

  3. Python Flask 在Sina App Engine (SAE)上安家

    早就听说了Python的大名,随着的编程语言的理解加深,越发认为动态语言的威力--真大呀. 趁这段时间不忙,我也用Python写了一个应用,而且将其部署到Sina App Engine (SAE).S ...

  4. MySQL 优化、设计规则浅谈

    当数据量大,数据库相应慢时都会针对数据库进行优化.这时都是要针对具体情况,具体业务需求进行优化的. 但是有些步骤和规则应该适合各种情况的.这里综合网上找的资料简单分析一下. 第一优化你的sql和索引: ...

  5. ORACLE物化视图具体解释

    一.物化的一般使用方法物化视图是一种特殊的物理表,"物化"(Materialized)视图是相对普通视图而言的.普通视图是虚拟表.应用的局限性大,不论什么对视图的查询.oracle ...

  6. ThreadLocal,LinkedBlockingQueue,线程池 获取数据库连接2改进

    package com.ctl.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQL ...

  7. 在一个JS文件中引用另一个JS文件

    方法一,在调用文件的顶部加入下例代码: document.write(”<script language=javascript src=’/js/import.js’></scrip ...

  8. C# 托管

    委托 委托让我们可以把函数引用保存在变量中.这就像在 C++ 中使用 typedef 保存函数指针一样. 委托使用关键字 delegate 声明.看看这个例子,你就能理解什么是委托: 例子: 代码: ...

  9. 【WPF】ComboBox:根据绑定选取、设置固定集合中的值

    问题场景 我有一个对象,里面有一个属性叫Limit,int类型.虽然int可取的范围很大,我想要在用户界面上限制Limit可取的值,暂且限制为5.10.15.20. 所以ComboBox绑定不是绑定常 ...

  10. python从安装与使用pip到入门

    官方下载地址:https://www.python.org/downloads/ 下载后直接安装就可以了 再配一下环境变量, cmd运行python -V (注意,这里是大写的V) 打开python跑 ...