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

在Linux系统中,它提供两种信号量:

  • 内核信号量,由内核控制路径使用

  • 用户态进程使用的信号量,这种信号量有两种接口,POSIX信号量和SYSTEM V信号量。

    信号量的本质是一个计数器。一个较为常见的用法,是为每个资源都会分配一个信号量。记信号量为S,除了初始化之外,有两个标准原子操作:wait()signal()

System V信号量接口

  • semget

    创建一个新信号量或取得一个已有信号量

    int semget(key_t key, int num_sems, int sem_flags);

    key是一个整数值(唯一非零),可以理解成是信号量的标识符。

    num_sems指定了需要的信号量数目,通常为1。

    sem_flags是一组标志,当创建一个新的信号量时,设定权限与值IPC_CREAT做按位或操作。设置了IPC_CREAT标志后,即使给出的键是一个已有信号量的键,也不会产生错误。而IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的信号量,如果信号量已存在,返回一个错误。

    函数成功返回一个相应信号标识符(非零),失败返回-1

  • semctl

    直接控制信号量信息

    int semctl(int sem_id, int sem_num, int command, ...);

    第二个参数是操作信号在信号集中的编号,第一个信号的编号是0

    第三个参数command通常是下面两个值中的其中一个:

    SETVAL:用来把信号量初始化为一个已知的值。

    IPC_RMID:用于删除一个已经无需继续使用的信号量标识符。

    如果有第四个参数,它通常是一个union semum结构,定义如下:

    union semun
    {
    int val;
    struct semid_ds *buf;
    unsigned short *arry;
    };
  • semop

    改变信号量的值

    int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);

    sem_id是由semget返回的信号量标识符,sembuf结构的定义如下:

    struct sembuf{
    short sem_num;//除非使用一组信号量,否则为0
    short sem_op;//信号量在一次操作中需要改变的数据,-1即P(等待)操作,+1即V(发送信号)操作。
    short sem_flg;//通常为SEM_UNDO,使操作系统跟踪信号,并在进程没有释放该信号量而终止时,操作系统释放信号量
    };

进程同步实例

无信号量实例
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h> int main()
{
pid_t pid;
pid = fork();
srand(pid);
if(pid > 0) // parent process
{
char a = 'A'; // char to print
for(int i = 0; i < 10; ++i)
{
printf("%c", a);
fflush(stdout); // flush stdout buffer
sleep(1); printf("%c", a);
fflush(stdout);
sleep(1);
}
}
else // child process
{
char b = 'B';
for(int i = 0; i < 10; ++i)
{
printf("%c", b);
fflush(stdout);
sleep(1); printf("%c", b);
fflush(stdout);
sleep(1);
}
}
printf("\n%d - finished\n", getpid());
sleep(3);
return 0;
}

运行结果

有信号量实例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h> #define SEMKEY 0x00002222 // set a key for semaphore union semun // union for semaphore
{
int val;
struct semid_ds *buf;
unsigned short *array;
}; struct sembuf p = { 0, -1, SEM_UNDO};
struct sembuf v = { 0, +1, SEM_UNDO}; int main()
{
int sem_id = semget(SEMKEY, 1, 0666 | IPC_CREAT); // get semaphore union semun sem_union;
sem_union.val = 1;
if(semctl(sem_id, 0, SETVAL, sem_union) < 0)
{
perror("semctl error");
return -1;
}
int pid;
pid = fork();
srand(pid);
if(pid > 0) // parent process
{
char a = 'A'; // char to print
for(int i = 0; i < 10; ++i)
{
if(semop(sem_id, &p, 1) < 0) // P operation
{
perror("semop p error");
return -1;
}
printf("%c", a);
fflush(stdout); // flush stdout buffer
sleep(1); printf("%c", a);
fflush(stdout);
if(semop(sem_id, &v, 1) < 0) // V operation
{
perror("semop v error");
return -1;
}
sleep(1);
}
}
else // child process
{
char b = 'B'; // char to print
for(int i = 0; i < 10; ++i)
{
if(semop(sem_id, &p, 1) < 0) // P operation
{
perror("semop p error");
return -1;
}
printf("%c", b);
fflush(stdout); // flush stdout buffer
sleep(1); printf("%c", b);
fflush(stdout);
if(semop(sem_id, &v, 1) < 0) // V operation
{
perror("semop v error");
return -1;
}
sleep(1);
}
}
printf("\n%d - finished\n", getpid());
sleep(3);
if (pid > 0)
{
system("ipcrm -S 0x00002222");
}
return 0;
}

运行结果

因为设定信号量的关系,一个线程在临界区内一定会执行两次print()操作,所以A或B一定成对出现。

Linux中的System V信号量的更多相关文章

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

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

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

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

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

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

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

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

  5. System V信号量

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

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

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

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

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

  8. 第11章 System V 信号量

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

  9. Linux IPC System V 信号量

    模型 #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> ftok() //获取key ...

随机推荐

  1. tar解压提示:tar (child): 无法连接至 xxxx: 解析失败

    如图提示: 错误原因:由于压缩文件中含有冒号导致 解决办法: 使用tar命令的–force-local选项

  2. Mysql-索引分析查询性能

    explain 全文只有一个关键点,那就是explain,explain 显示了MySQL如何使用索引来处理select语句以及连接表.可以帮助选择更好的索引和写出更优化的查询语句.简单讲,它的作用就 ...

  3. TextClip的list和search方法报错:UnicodeDecodeError: utf-8 codec canot decode byte 0xb7 in position 8

    ☞ ░ 前往老猿Python博文目录 ░ 由于moviepy对多语言环境支持存在一些问题,因此在执行TextClip.list('font')和TextClip.search('GB','font') ...

  4. PyQt(Python+Qt)学习随笔:QTabWidget选项卡部件的currentWidget和widget方法

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QTabWidget的每个选项卡都有一个对应的页面部件对象,可用通过currentWidget方法和 ...

  5. PyQt(Python+Qt)学习随笔:QTableWidget的findItems和selectedItems搜索项和访问选中项方法

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 1.搜索项 在表格部件中,可以根据文本以及匹配模式来搜索满足条件的项,调用语法: list[QTab ...

  6. PyQt(Python+Qt)学习随笔:QAbstractItemView的selectionMode属性

    老猿Python博文目录 老猿Python博客地址 一.概述 selectionMode属性用于控制view中操作选择数据项的模式,用于控制用户是否可以选择一个或多个数据项,以及在多个数据项选择中,选 ...

  7. PyQt(Python+Qt)学习随笔:Qt Designer中主窗口对象的tabShape属性

    tabShape属性用于控制主窗口标签部件(Tab Widget)中的标签的形状,对应类型为QTabWidget.TabShape,有两种取值: 1.QTabWidget.Rounded:对应值为0, ...

  8. 常见的HTML元素及常见检查点

    1.<select>标签,可创建单选或多选菜单 检查点:下拉列表数据的正确性.数据被选中是否正确.是否变形.是否只读.多选/单选是否正确 2.<label>标签,相当于一个展示 ...

  9. 落谷 P4052 [JSOI2007]文本生成器

    题目链接.只要有一个可读就行,容斥会好做一点. 可读数量 \(=\) 总数 \(-\) 不可读数量 总数显然是 \(26 ^ n\). 求解不可读数量 不可读数量可以利用 AC 自动机的模型进行 DP ...

  10. ps查看完整程序执行路径

    在linux下查看进程大家都会想到用 ps -ef|grep ***可是看到的不是全路径,怎么看全路径呢?每个进程启动之后在 /proc下面有一个于pid对应的路径例如:ps -ef|grep jav ...