信号量

信号量和P、V原语由Dijkstra(迪杰斯特拉)提出

信号量:

  • 互斥: P、V在同一进程中
  • 同步: P、V在不同进程中

信号量值含义

  • S>0 : S表示可用资源个数
  • S=0 : 表示无可用资源,无等待进程
  • S<0 : |S|表示等待队列中进程个数

信号量集结构

struct semid_ds {
struct ipc_perm sem_perm; /* Ownership and permissions */
time_t sem_otime; /* Last semop time */
time_t sem_ctime; /* Last change time */
unsigned long sem_nsems; /* No. of semaphores in set */
};

信号量集函数

semget

int semget(key_t key, int nsems, int semflg);
功能:
创建或访问一个信号量集
参数:
key : 信号集的名字
nsems : 信号集中信号量的个数
semflg : 由9个权限位标志构成,它们的用法与创建文件时使用的mode模式标志是一样的
返回值:
成功 : 返回一个非负整数,即该信号集的表示码
失败 : -1

semctl

int semctl(int semid, int semnum, int cmd, ...);
功能:
用于控制信号量集
参数:
semid : 由semget返回的信号集标识码
semnum : 信号集中信号量的序号
cmd : 将要采取的动作
SETVAL : 设置信号量集中的信号量的计数值
GETVAL : 获取信号量集中的信号量的计数值
IPC_STAT :把semid_ds结构中的数据设置为信号集的当前关联值
IPC_SET :在进程有足够的权限的前提下,把信号集的当前关联值设置为semid_ds数据结构中给出的值
IPC_RMID:删除信号集 最后一个参数根据命令不同而不同 返回值:
成功 : 0
失败 : -1

semop

int semop(int semid, struct sembuf *sops, size_t nsops);

功能:
操作一个或一组信号
参数:
semid : 信号量的标识码,也就是semget函数的返回值
sops : 指向一个结构数值的指针
struct sembuf{
unsigned short sem_num; /* semaphore number 信号量的编号*/
short sem_op; /* semaphore operation 信号量一次PV操作时加减的数值*/
/* =0 操作会阻塞,直到信号量的计数变为0才返回(等待资源变为0)*/
/*-1, 也就是P操作,等待信号量变得可用*/
/*+1, 也就是V操作,发出信号量已经变得可用*/
short sem_flg; /* operation flags IPC_NOWAIT|SEM_UNDO */
/* IPC_NOWAIT P、V操作不阻塞直接返回 Resource temporarily unavailable */
/* SEM_UNDO 进行P、V操作的进程结束后,操作会被撤销,资源会被归还,资源的计数值会恢复*/
}
nsops : 信号量的个数
返回值:
成功 : 0
失败 : -1

semget.c

#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h> #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h> union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
}; #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0) int sem_create(key_t key)
{
int semid;
semid = semget(key, 1, IPC_CREAT|IPC_EXCL| 0666);
if(semid == -1)
ERR_EXIT("semget"); return semid;
} int sem_open(key_t key)
{
int semid;
semid = semget(key, 0, 0);
if(semid == -1)
ERR_EXIT("semget"); return semid;
} int sem_setval(int semid, int val)
{
union semun su;
su.val = val;
int ret;
ret = semctl(semid, 0, SETVAL, su);
if(ret == -1)
ERR_EXIT("semctl"); return 0;
} int sem_del(int semid)
{
int ret;
ret = semctl(semid, 0, IPC_RMID, 0);
if(ret == -1)
ERR_EXIT("semctl"); return 0;
} int sem_getval(int semid, int val)
{
int ret;
ret = semctl(semid, 0, GETVAL, 0);
if(ret == -1)
ERR_EXIT("semctl getval"); return ret;
} int sem_p(int semid)
{
// 0 对信号量集中的第一个信号进行操作
// -1 对信号量的操作是P操作,对信号量的计数值-1
struct sembuf sops = {0, -1, 0};
int ret;
//第二个参数是指针,指针可以指向数组,数组可以保存多个对信号量集的操作
ret = semop(semid, &sops, 1);
if(ret == -1)
ERR_EXIT("semop"); return 0;
} int sem_v(int semid)
{
struct sembuf sops = {0, 1, 0};
int ret;
ret = semop(semid, &sops, 1);
if(ret == -1)
ERR_EXIT("semop"); return 0;
} int main(int argc, char* argv[])
{ int semid;
semid = sem_create(1234);
sleep(5);
sem_del(semid); return 0;
}

信号量示例

semtool.c

#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h> union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
}; #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0) int sem_create(key_t key)
{
int semid;
semid = semget(key, 1, IPC_CREAT | IPC_EXCL | 0666);
if (semid == -1)
ERR_EXIT("semget"); printf("sem created...\n"); return semid;
} int sem_del(int semid)
{
int ret;
ret = semctl(semid, 0, IPC_RMID, 0);
if (ret == -1)
ERR_EXIT("semctl"); printf("sem deleted...\n");
return 0;
} int sem_open(key_t key)
{
int semid;
semid = semget(key, 0, 0);
if (semid == -1)
ERR_EXIT("semget"); return semid;
} int sem_setval(int semid, int val)
{
union semun su;
su.val = val;
int ret;
ret = semctl(semid, 0, SETVAL, su);
if (ret == -1)
ERR_EXIT("semctl"); printf("sem value updated...\n"); return 0;
} int sem_getval(int semid)
{
int ret;
ret = semctl(semid, 0, GETVAL, 0);
if (ret == -1)
ERR_EXIT("semctl getval"); printf("current value is %d\n", ret);
return ret;
} int sem_p(int semid)
{
// struct sembuf sops = {0, -1, 0}; //0 , 当p操作减为0, 阻塞
//IPC_NOWAIT, 当p操作减为0, Resource temporarily unavailable
//IPC_UNDO, 进行一次p操作会减1,假如进程结束了,p操作会被撤销,资源会被归还,资源的计数值会恢复
struct sembuf sops = {0, -1, /*0*//* IPC_NOWAIT */SEM_UNDO};
int ret; ret = semop(semid, &sops, 1);
if (ret == -1)
ERR_EXIT("semop"); return 0;
} int sem_v(int semid)
{
// struct sembuf sops = {0, 1, 0};
//当进程终止时,操作会被撤销,资源会被归还,资源计数会恢复
struct sembuf sops = {0, -1, /*0*//* IPC_NOWAIT */SEM_UNDO};
int ret; ret = semop(semid, &sops, 1);
if (ret == -1)
ERR_EXIT("semop"); return 0;
} int sem_getmode(int semid)
{
union semun su;
struct semid_ds sem;
su.buf = &sem; int ret = semctl(semid, 0, IPC_STAT, su);
if(ret == -1)
ERR_EXIT("senctl"); printf("current permission is %o\n", su.buf->sem_perm.mode);
return ret;
} int sem_setmode(int semid, char* mode)
{
union semun su;
struct semid_ds sem;
su.buf = &sem; int ret = semctl(semid, 0, IPC_STAT, su);
if(ret == -1)
ERR_EXIT("senctl");
printf("current permission is %o\n", su.buf->sem_perm.mode); sscanf(mode, "%o", (unsigned int*)&su.buf->sem_perm.mode);
ret = semctl(semid, 0, IPC_SET, su);
if(ret == -1)
ERR_EXIT("senctl"); printf("permissions updated...\n"); return ret;
} void usage()
{
fprintf(stderr,"usage:\n");
fprintf(stderr,"semtool -c\n");
fprintf(stderr,"semtool -d\n");
fprintf(stderr,"semtool -p\n");
fprintf(stderr,"semtool -v\n");
fprintf(stderr,"semtool -s <val>\n");
fprintf(stderr,"semtool -g\n");
fprintf(stderr,"semtool -f\n");
fprintf(stderr,"semtool -m <mode>\n");
} int main(int argc, char *argv[])
{ int opt;
opt = getopt(argc, argv, "cdpvs:gfm:");
if (opt == '?')
exit(EXIT_FAILURE); if(opt == -1)
{
usage();
exit(EXIT_FAILURE);
} key_t key = ftok(".",'s');
int semid; switch (opt)
{
case 'c':
sem_create(key);
break;
case 'p':
semid = sem_open(key);
sem_p(semid);
sem_getval(semid);
break;
case 'v':
semid = sem_open(key);
sem_v(semid);
sem_getval(semid);
break;
case 'd':
semid = sem_open(key);
sem_del(semid);
break;
case 's':
semid = sem_open(key);
sem_setval(semid, atoi(optarg));
break;
case 'g':
semid = sem_open(key);
sem_getval(semid);
break;
case 'f':
semid = sem_open(key);
sem_getmode(semid);
break;
case 'm':
semid = sem_open(key);
sem_setmode(semid, argv[2]);
break; default:
break;
} return 0;
}

第三十章 System V信号量(一)的更多相关文章

  1. System V信号量

    信号量对比 二值信号量:其值要么0要么1,比如互斥锁就是这种类型 计数信号量:其值为0或某个正整数,比如POSIX 信号量 计数信号量:一个或多个信号量构成一个集合,每个都是计数信号量,比如Syste ...

  2. Linux IPC实践(11) --System V信号量(1)

    信号量API #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semget ...

  3. System V 信号量使用相关函数

    System V 信号量 在提到Posix 信号量时,指的是二值信号量或计数信号量,而System V信号量指的是入了计数信号量集 二值信号量:其值为0或1,类似于互斥锁,资源被锁住时为0,资源可用为 ...

  4. linux网络编程之system v信号量(一)

    今天起,学习信号量相关的知识,下面开始: 关于信号量,在前面已经介绍过了,这里回顾一下: 通过上面的描述,很容易就能想到信号量的一上数据结构: 下面再来回顾一下P.V原语: 所谓的原语就是指这段代码是 ...

  5. Linux中的System V信号量

    在进程同步,并发运行时,保证按序地访问共享资源是十分重要的.因此引入了临界区的概念,一次只能有一个线程进入临界区完成他的指令.而信号量(semaphore)的作用,类似于一个交通信号灯,它负责进程协作 ...

  6. system V信号量和Posix信号量

    一.函数上的区别 信号量有两种实现:传统的System V信号量和新的POSIX信号量.它们所提供的函数很容易被区分:对于所有System V信号量函数,在它们的名字里面没有下划线.例如,应该是sem ...

  7. 第11章 System V 信号量

    11.1 概述 信号量按功能分:二值信号量.计数信号量.信号量集:其中二值信号量和计数信号量指的是Posix信号量,信号量集指的是System V信号量.

  8. UNIX环境高级编程——system V信号量

    1. 信号量(semaphore)主要用于保护临界资源.进程可以根据它判断是否能访问某些共享资源.信号量除了用于访问控制外,还可用于进程同步,也就是进程间通信.2. 信号量分类:a. 二值信号量: 信 ...

  9. linux网络编程之system v信号量(二)

    今天迎来元旦假期的最后一天了,过得好快~昨天跟小伙伴们在军都滑雪陪儿爽,虽说上了两回中级道都摔得异常的惨烈,但是在初级道上学习"s"转弯还是有一些小心得,可以在要往高手迈进的前提, ...

随机推荐

  1. VirtualBox 安装摄像头驱动

    1. 需下载与VM Virtualbox相匹配的驱动,因为我的虚拟机版本是5.2.8,所以就下载5.2版本的驱动: https://www.virtualbox.org/wiki/Download_O ...

  2. 概率与期望详解!一次精通oi中的概率期望

    目录 基础概念 最大值不超过Y的期望 概率为P时期望成功次数 基础问题 拿球 随机游走 经典问题 期望线性性练习题 例题选讲 noip2016换教室 区间交 0-1边树求直径期望 球染色 区间翻转 二 ...

  3. jQuery常用方法(五)-jQuery CSS

    JQuery CSS 方法说明 css( name ) 访问第一个匹配元素的样式属性. css( properties ) 把一个"名/值对"对象设置为所有匹配元素的样式属性. $ ...

  4. Python3爬虫基础实战篇之机票数据采集

    项目:艺龙国内机票实时数据爬虫 使用模块:requests(请求模块),js2py(js执行模块),json(解析json),xpath(解析网页). 项目流程: 分析网站数据来源. 编写爬虫脚本. ...

  5. 夯实Java基础系列22:一文读懂Java序列化和反序列化

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  6. Java 学习笔记之 实例变量非线程安全

    实例变量非线程安全: 如果多个线程共同访问1个对象中的实例变量,则可能出现“非线程安全”问题. public class UnSafeHasSelfPrivateNum { private int n ...

  7. IDEA 学习笔记之 Web项目开发

    Web项目开发: 添加新模块: 起名: 添加jars: 添加Tomcat/local: 添加项目:  启动Tomcat: 看到web页面: 修改页面: 重新部署页面:

  8. Laravel Entrust 权限管理扩展包的使用笔记

    简介 Entrust 是一个简洁而灵活的基于角色进行权限管理的 Laravel 扩展包.针对 Laravel 5,官方推荐的安装版本是 5.2.x-dev.它的详细使用方法请查看 Entrust Gi ...

  9. React 项目引入 Dva

    背景 现在手上在做的 React 项目因为年代久远,用的 Redux,写代码的体验不太好,所以想升级一下引入 dva.以往使用 dva 都是使用 dva-cli 直接生成 dva 项目,或者在使用 a ...

  10. 时间复杂度————被list.insert坑了

    今天被一个很简单的坑到了,还想了很长时间,insert 函数,真的知道它内部执行的操作吗? 开始其实是在看一本算法的书,书里面给了两段工作内容差不多的伪代码 第一段如下: data = [] whil ...