【Linux基础】信号量

号量是一个非负的整数计数器,是操作系统中所用到的PV原语,它主要应用于进程或线程间的同步与互斥。那么PV原语是什么呢?PV原语的工作原理如下:
PV原语是对整数计数器信号量sem的操作。一次P操作使sem减一,而一次V操作,使sem加一。线程(或进程)根据信号量的值来判断是否对公共资源具有访问权限。当信号量sem的值大于等于零时,该线程(或进程)具有公共资源的访问权限;相反,当信号量sem的值小于零时,该线程(或进程)就将阻塞直到信号量sem的值大于等于0为止。
1. PV原语主要用于进程或线程间的同步和互斥这两种典型情况
(1) 用于互斥,几个线程(或进程)往往只设置一个信号量sem,它们的操作流程如所示

01.jpg (22.57 KB, 下载次数: 0)

下载附件 保存到相册 设为封面

2013-6-7 09:12 上传

(2) 当信号量用于同步操作时,往往设置多个信号量,并安排不同的初始值来实现它们之间的顺序执行,它们的操作流程如所示

02.jpg (24.21 KB, 下载次数: 0)

下载附件 保存到相册 设为封面

2013-6-7 09:12 上传

2. 函数格式
在使用信号量时所涉及到以下函数:函数sem_init用于创建信号量,并初始化其值;函数sem_wait和函数sem_trywait相当于P操作,是将信号量的值减一,其区别在于若信号量小于零时,sem_wait将会阻塞进程,而sem_trywait则会立即返回;函数sem_post相当于V操作,它将信号量的值加一同时发出信号唤醒等待的进程;函数sem_getvalue用于得到信号量的值;函数sem_destroy用于删除信号量。
(1)sem_init函数的语法要点
sem_init函数的语法要点

03.jpg (42.31 KB, 下载次数: 0)

下载附件 保存到相册 设为封面

2013-6-7 09:13 上传

04.jpg (35.67 KB, 下载次数: 0)

下载附件 保存到相册 设为封面

2013-6-7 09:14 上传

3. 函数实例
实例1:
(1)实例内容
使用信号量实现了两线程是互斥操作,也就是只使用一个信号量来实现。
(2)实例代码
/*sem_mutex.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/ipc.h>
#include <semaphore.h>
int lock_var;
time_t end_time;
sem_t sem
void pthread1(void *arg);
void pthread2(void *arg);
int main(int argc, char *argv[])
{
pthread_t id1,id2;
pthread_t mon_th_id;
int ret;
end_time = time(NULL)+30;
/*初始化信号量为 1*/
ret=sem_init(&sem,0,1);
if(ret!=0)
{
perror("sem_init");
}
/*创建两个线程*/
ret=pthread_create(&id1,NULL,(void *)pthread1, NULL);
if(ret!=0)
perror("pthread cread1");
ret=pthread_create(&id2,NULL,(void *)pthread2, NULL);
if(ret!=0)
perror("pthread cread2");
pthread_join(id1,NULL);
pthread_join(id2,NULL);
exit(0);
}
void pthread1(void *arg)
{
int i;
while(time(NULL) < end_time)
{
/*信号量减一,P 操作*/
sem_wait(&sem);
for(i=0;i<2;i++)
{
sleep(1);
lock_var++;
printf("lock_var=%d\n",lock_var);
}
printf("pthread1:lock_var=%d\n",lock_var);
/*信号量加一,V 操作*/
sem_post(&sem);
sleep(1);
}
}
void pthread2(void *arg)
{
int nolock=0;
int ret;
while(time(NULL) < end_time){
/*信号量减一,P 操作*/
sem_wait(&sem);
printf("pthread2:pthread1 got lock;lock_var=%d\n",lock_var);
/*信号量加一,V 操作*/
sem_post(&sem);
sleep(3);
}
}
程序运行结果如下所示:
[root@(none) tmp]# ./sem_num
lock_var=1
lock_var=2
pthread1:lock_var=2
pthread2:pthread1 got lock;lock_var=2
lock_var=3
lock_var=4
pthread1:lock_var=4
pthread2:pthread1 got lock;lock_var=4
实例2
(1)实例内容
通过两个信号量来实现两个线程间的同步。
(2)实例代码
/*sem_syn.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/ipc.h>
#include <semaphore.h>
int lock_var;
time_t end_time;
sem_t sem1,sem2;
void pthread1(void *arg);
void pthread2(void *arg);
int main(int argc, char *argv[])
{
pthread_t id1,id2;
pthread_t mon_th_id;
int ret;
end_time = time(NULL)+30;
/*初始化两个信号量,一个信号量为 1,一个信号量为 0*/
ret=sem_init(&sem1,0,1);
ret=sem_init(&sem2,0,0);
if(ret!=0)
{
perror("sem_init");
}
/*创建两个线程*/
ret=pthread_create(&id1,NULL,(void *)pthread1, NULL);
if(ret!=0)
perror("pthread cread1");
ret=pthread_create(&id2,NULL,(void *)pthread2, NULL);
if(ret!=0)
perror("pthread cread2");
pthread_join(id1,NULL);
pthread_join(id2,NULL);
exit(0);
}
void pthread1(void *arg)
{
int i;
while(time(NULL) < end_time){
/*P 操作信号量 2*/
sem_wait(&sem2);
for(i=0;i<2;i++)
{
sleep(1);
lock_var++;
printf("lock_var=%d\n",lock_var);
}
printf("pthread1:lock_var=%d\n",lock_var);
/*V 操作信号量 1*/
sem_post(&sem1);
sleep(1);
}
}
void pthread2(void *arg)
{
int nolock=0;
int ret;
while(time(NULL) < end_time){
/*P 操作信号量 1*/
sem_wait(&sem1);
printf("pthread2:pthread1 got lock;lock_var=%d\n",lock_var);
/*V 操作信号量 2*/
sem_post(&sem2);
sleep(3);
}
}
从以下结果中可以看出,该程序确实实现了先运行线程二,再运行线程一。
[root@(none) tmp]# ./sem_num
pthread2:pthread1 got lock;lock_var=0
lock_var=1
lock_var=2
pthread1:lock_var=2
pthread2:pthread1 got lock;lock_var=2
lock_var=3
lock_var=4
pthread1:lock_var=4

本文转载于唯C教育,【Linux基础】信号量
http://www.weicedu.com/forum.php?mod=viewthread&tid=123&fromuid=4
(出处: http://www.weicedu.com/)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值