system V信号量和Posix信号量
一、函数上的区别
信号量有两种实现:传统的System V信号量和新的POSIX信号量。它们所提供的函数很容易被区分:对于所有System V信号量函数,在它们的名字里面没有下划线。例如,应该是semget()而不是sem_get()。然而,所有的的POSIX信号量函数都有一个下划线。下面列出了它们提供的所有函数清单:
| Systm V | POSIX |
| semctl() | sem_getvalue() |
| semget() | sem_post() |
| semop() | sem_timedwait() |
| sem_trywait() | |
| sem_wait() | |
| sem_destroy() | |
| sem_init() | |
| sem_close() | |
| sem_open() | |
| sem_unlink() |
二、使用上的区别
1、XSI system V的信号量是信号量集,可以包括多个信号灯(有个数组),每个操作可以同时操作多个信号灯
posix是单个信号灯,POSIX有名信号灯支持进程间通信,无名信号灯放在共享内存中时可以用于进程间通信。
2、POSIX信号量在有些平台并没有被实现,比如:SUSE8,而SYSTEM V大多数LINUX/UNIX都已经实现。两者都可以用于进程和线程间通信。但一般来说,system v信号量用于 进程间同步、有名信号灯既可用于线程间的同步,又可以用于进程间的同步、posix无名用于同一个进程的不同线程间,如果无名信号量要用于进程间同步,信号量要放在共享内存中。
3、POSIX有两种类型的信号量,有名信号量和无名信号量。有名信号量像system v信号量一样由一个名字标识。
4、POSIX通过sem_open单一的调用就完成了信号量的创建、初始化和权限的设置,而system v要两步。也就是说posix 信号是多线程,多进程安全的,而system v不是,可能会出现问题。
5、system V信号量通过一个int类型的值来标识自己(类似于调用open()返回的fd),而sem_open函数返回sem_t类型(长整形)作为posix信号量的标识值。
6、对于System V信号量你可以控制每次自增或是自减的信号量计数,而在Posix里面,信号量计数每次只能自增或是自减1。
7、Posix无名信号量提供一种非常驻的信号量机制。
8、相关进程: 如果进程是从一已经存在的进程创建,并最终操作这个创建进程的资源,那么这些进程被称为相关的。
三、注意事项
1、Posix有名信号灯的值是随内核持续的。也就是说,一个进程创建了一个信号灯,这个进程结束后,这个信号灯还存在,并且信号灯的值也不会改变。当持有某个信号灯锁的进程没有释放它就终止时,内核并不给该信号灯解锁
2、posix有名信号灯是通过内核持续的,一个进程创建一个信号灯,另外的进程可以通过该信号灯的外部名(创建信号灯使用的文件名)来访问它。posix基于内存的无名信号灯的持续性却是不定的,如果基于内存的信号灯是由单个进程内的各个线程共享的,那么该信号灯就是随进程持续的,当该进程终止时它也会消失。如果某个基于内存的信号灯是在不同进程间同步的,该信号灯必须存放在共享内存区中,这要只要该共享内存区存在,该信号灯就存在。
四、总结
1、System V的信号量一般用于进程同步, 且是内核持续的, api为:semget、semctl、semop
2、Posix的有名信号量一般用于进程同步, 有名信号量是内核持续的. 有名信号量的api为:sem_open、sem_close、sem_unlink
3、Posix的无名信号量一般用于线程同步, 无名信号量是进程持续的, 无名信号量的api为:sem_init、sem_destroy
五、代码示例
<span style="background-color: rgb(255, 255, 255);">/*</span><span style="background-color: rgb(255, 255, 252);">
* MultiProcessLock.cpp
*
* Created on: 2013-8-28
* Detail: System V 信号量的使用
*/ #include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <errno.h> // val当执行SETVAL命令时使用。buf在IPC_STAT/IPC_SET命令中使用。代表了内核中使用的信号量的数据结构。array在使用GETALL/SETALL命令时使用的指针。
union semun
{
int val; /*value for SETVAL*/
struct semid_ds *buf; /*buffer for IPC_STAT & IPC_SET*/
unsigned short int *array; /*array for GETALL & SETALL*/
struct seminfo *__buf; /*buffer for IPC_INFO*/
}; /* 等待一个二元信号量:阻塞直到信号量的值为正,然后将其减1 */
int binary_semaphore_wait(int semid)
{
struct sembuf sem_b; sem_b.sem_num = 0;
/* 减一。 */
sem_b.sem_op = -1;
/* 允许撤销操作 */
sem_b.sem_flg = SEM_UNDO;
return semop (semid, &sem_b, 1);
} /* 对一个二元信号量执行投递操作:将其值加一。 这个操作会立即返回 */
int binary_semaphore_post (int semid)
{
struct sembuf sem_b;
/* 使用(且仅使用)第一个信号量 */
sem_b.sem_num = 0;
/* 加一 */
sem_b.sem_op = 1;
/* 允许撤销操作 */
sem_b.sem_flg = SEM_UNDO;
return semop (semid, &sem_b, 1);
} int main()
{
int iSemId;
int nsems = 1; /*
* 通过 IPC_CREAT | IPC_EXCL 可以判断这个key对应的信号量是不是已经存在了,这可以用在单进程运行多次的情况下,只初始化一次信号量的情况下
*/
int semflg = 0666 | IPC_CREAT | IPC_EXCL; // 如果key对应的((semflg &IPC_CREAT) &&(semflg &IPC_EXCL))非0, 那么semget返回EEXIST
key_t key = (key_t)0x20130828; /*创建一个新的信号量集*/
iSemId = semget(key, nsems, semflg);
if (iSemId < 0 && errno != EEXIST)
{
perror( "semget ") ;
return -1;
} if(iSemId >= 0) // 这个信号量是第一次创建,则初始化
{
printf("create: semid is %d\n", iSemId);
/* 初始化信号量 */
semun sem_union;
sem_union.val = 1;
if(semctl(iSemId, 0, SETVAL, sem_union) == -1)
{
perror("semctl");
return -1;
}
}
else // 这个信号量已经有了,则获得这个信号量值
{
iSemId = semget(key, nsems, 0666);
printf("exit: semid is %d\n", iSemId);
} /* 进程同步执行 */
for(int i = 0; i < 10; ++i)
{
if(binary_semaphore_wait(iSemId))
{
perror("semop: ");
exit(-1);
}
printf("%d ", getpid());
sleep(1);
printf("%d\n", getpid());
if(binary_semaphore_post(iSemId))
{
exit(-1);
} } return 0;
}</span>
/* posixSemProgessLock.cpp
*
* Created on: 2013-8-29
* Detail: 使用Posix信号量的进程同步
*/ #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <fcntl.h> #define SEM_NAME "0x20130829" int main()
{
/* 初始化一个有名二元信号灯 */
sem_t *sem;
sem = sem_open(SEM_NAME, O_CREAT, 0666, 10);
if(sem == SEM_FAILED)
{
perror("sem init failed:");
return -1;
} int val;
sem_wait(sem);
sem_getvalue(sem,&val);
printf("1: getvalue: value=%d, pid=%d\n",val, getpid());
sleep(1);
printf("2: getvalue: value=%d, pid=%d\n",val, getpid());
sem_post(sem);
sleep(1);
sem_getvalue(sem,&val);
printf("3: getvalue: value=%d, pid=%d\n",val, getpid());
sem_unlink(SEM_NAME);
return 0;
}
PV原子操作主要用于进程或线程间的同步和互斥这两种典型情况。若用于互斥,几个进程(或线程)往往只设置一个信号量sem。 当信号量用于同步操作时,往往会设置多个信号量,并安排不同的初始值来实现它们之间的顺序执行,下面是一个线程同步的例子:
/*thread_sem.c*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h> #define THREAD_NUMBER 3 /* 线程数 */
#define REPEAT_NUMBER 3 /* 每个线程中的小任务数 */
#define DELAY_TIME_LEVELS 10.0 /*小任务之间的最大时间间隔*/
sem_t sem[THREAD_NUMBER]; void *thrd_func(void *arg)
{
int thrd_num = (int)arg;
int delay_time = 0;
int count = 0;
/* 进行P操作 */
sem_wait(&sem[thrd_num]);
printf("Thread %d is starting\n", thrd_num); for (count = 0; count < REPEAT_NUMBER; count++)
{
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + 1;
sleep(delay_time);
printf("\tThread %d: job %d delay = %d\n", thrd_num, count, delay_time);
} printf("Thread %d finished\n", thrd_num);
pthread_exit(NULL);
} int main(void)
{
pthread_t thread[THREAD_NUMBER];
int no = 0, res;
void * thrd_ret; srand(time(NULL));
for (no = 0; no < THREAD_NUMBER; no++)
{
sem_init(&sem[no], 0, 0);
int val;
sem_getvalue(&sem[no],&val);
printf("val is %d\n", val);
res = pthread_create(&thread[no], NULL, thrd_func, (void*)no);
if (res != 0)
{
printf("Create thread %d failed\n", no);
exit(res);
}
} printf("Create treads success\n Waiting for threads to finish...\n");
/* 对最后创建的线程的信号量进行V操作 */
sem_post(&sem[THREAD_NUMBER - 1]);
for (no = THREAD_NUMBER - 1; no >= 0; no--)
{
res = pthread_join(thread[no], &thrd_ret);
if (!res)
{
printf("Thread %d joined\n", no);
}
else
{
printf("Thread %d join failed\n", no);
}
/* 进行V操作 */
sem_post(&sem[(no + THREAD_NUMBER - 1) % THREAD_NUMBER]);
} for (no = 0; no < THREAD_NUMBER; no++)
{
/* 删除信号量 */
sem_destroy(&sem[no]);
}
return 0;
}
system V信号量和Posix信号量的更多相关文章
- 五十一、进程间通信——System V IPC 之进程信号量
51.1 进程信号量 51.1.1 信号量 本质上就是共享资源的数目,用来控制对共享资源的访问 用于进程间的互斥和同步 每种共享资源对应一个信号量,为了便于大量共享资源的操作引入了信号量集,可对所有信 ...
- system v共享内存与信号量综合
ipc.h #include <sys/types.h> #include <unistd.h> #include <sys/ipc.h> #include < ...
- 第三十三章 System V共享内存与信号量综合
用信号量解决生产者.消费者问题 实现shmfifo ip.h #ifndef _IPC_H #define _IPC_H #include <unistd.h> #include < ...
- System V IPC 之信号量
本文继<System V IPC 之共享内存>之后接着介绍 System V IPC 的信号量编程.在开始正式的内容前让我们先概要的了解一下 Linux 中信号量的分类. 信号量的分类 在 ...
- Linux进程通信 之 信号灯(semphore)(System V && POSIX)
一. 信号灯简介 信号灯与其他进程间通信方式不大相同,它主要提供对进程间共享资源访问控制机制. 相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源,同时,进程 也可以修改该标志.除了用于访 ...
- linux Posix 信号量 二
一.Posix信号量 1.Posix信号量分为两种: 1. 有名信号量:使用Posix IPC名字标识(有名信号量总是既可用于线程间的同步,又可以用于进程间的同步) 2. 内存信号量:存放在共 ...
- UNIX 进程间通讯(IPC)概念(Posix,System V IPC)
IPC(Inter-Process Communication,进程间通讯)可以有三种信息共享方式(随文件系统,随内核,随共享内存).(当然这里虽然说是进程间通讯,其实也是可以和线程相通的). 相对 ...
- 多线程编程之Apue3rd_Chapter15.10之posix信号量
看了APUE的chapter15,只重点看了15.10,学习了posix信号量.Posix信号量比起xsi信号量的优点是性能更好,在Linux3.2.0平台上性能提升很大.其中命名信号量使用方法如下. ...
- System V IPC
1.概述 System V IPC共有三种类型:System V消息队列.System V 信号量.System V 共享内存区. System V IPC操作函数如下: 2.key_t键和ftok函 ...
随机推荐
- AcWing 1273. 天才的记忆
从前有个人名叫 WNB,他有着天才般的记忆力,他珍藏了许多许多的宝藏. 在他离世之后留给后人一个难题(专门考验记忆力的啊!),如果谁能轻松回答出这个问题,便可以继承他的宝藏. 题目是这样的:给你一大串 ...
- 第二章 - Java与协程
Java与协程 内核线程的局限 通过一个具体场景来解释目前Java线程面临的困境.今天对Web应用的服务要求,不论是在请求数量上还是在复杂度上,与十多年前相比已不可同日而语,这一方面是源于业务量的增长 ...
- FreeRTOS消息队列
FreeRTOS 的一个重要的通信机制----消息队列,消息队列在实际项目中应用较多. 一.消息队列的作用及概念: 消息队列就是通过 RTOS 内核提供的服务,任务或中断服务子程序可以将一个消息(注意 ...
- 家庭账本开发day09
编写数据表格的编辑操作,大体思路和删除操作一样 点击按钮,弹出修改项目,从父窗口获取已有的值赋给 弹出的子窗口中相应的值,在子窗口中点击提交,ajax请求 servlet修改.成功后重载表格,或者up ...
- 高校表白App-团队冲刺第九天
今天要做什么 在Fragment首页加上轮转播报,点击图片进入相应连接 做了什么 功能实现,通过连接第三方库来进行实现,比较简单.(url就可以) 遇到的问题 在调用以前的工具类时,有点小问题,发现以 ...
- IO编程之File类
File类是java.io包下代表与平台无关的文件及目录,程序操作文件和目录都可以通过File类来完成.值得指出的是,不管是文件还是目录都可以通过File类来操作.File能新建.删除.重命名文件和目 ...
- debian9 独显安装后进入不了桌面解决方法
# apt-get purge nvidia. # /etc/init.d/sddm stop (sddm for kde) # aptitude --without-recommends insta ...
- YsoSerial 工具常用Payload分析之CC5、6(三)
前言 这是common-collections 反序列化的第三篇文章,这次分析利用链CC5和CC6,先看下Ysoserial CC5 payload: public BadAttributeValue ...
- 项目启动报错 The server time zone value '�й���ʱ��' is unrecognize...
背景介绍: 把项目在新的电脑上运行,MySQL版本不同出现错误 错误: 报错The server time zone value '�й���ʱ��' is unrecognized or repr ...
- 7.15考试总结(NOIP模拟16)[Star Way To Heaven·God Knows·Lost My Music]
败者死于绝望,胜者死于渴望. 前言 一看这个题就来者不善,对于第一题第一眼以为是一个大模拟,没想到是最小生成树. 对于第二题,先是看到了状压可以搞到的 20pts 然后对着暴力一顿猛调后来发现是题面理 ...