浅析Posix信号灯

[b][size=large][align=center]Posix信号灯[/align][/size][/b]

信号灯分为有名信号灯和内存信号灯,本文只讲有名信号灯。

一 有名信号灯API

1.sem_open

函数原形:sem_t *sem_open(const char *name,int oflag,/*mode_t mode,unsigned int value*/);

参数:
name 信号灯的外部名字
oflag 选择创建或打开一个现有的信号灯
mode 权限位
value 信号灯初始值,二值信号灯为1,非二值信号灯大于1
返回值:
成功时返回指向信号灯的指针,出错时为SEM_FAILED

2.sem_close

#include<semaphore.h>
int sem_close(sem_t *sem);

返回:成功是返回0,出错是返回-1

一个进程终止时,内核对其上的仍然打开的所有的有名信号灯自动执行sem_close操作,即关闭信号灯。不论该进程是自愿终止的还是非自愿终止的,这种关闭动作都会发生。

关闭一个信号灯并内有将它从系统中删除。这就是说,Posix有名信号灯至少是随内核持续的:即使当前没有进程打开着某个信号灯,它的值仍然保存。

3.sem_unlink

#include<semaphore.h>
int sem_unlink(const char*name);

有名信号使用sem_unlink从系统中删除。

4.sem_wait
#include<semaphore.h>
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);

sem_wait函数测试所指定信号灯的值,如果该值大于0,那就将它减1,并立即返回。如果该值等于0,调用线程就被投入休眠中,即被挂起,直到其值大于0,这时再将它减1,函数随后返回。

注意这里的机制和互斥锁和条件变量的不同,条件变量是和互斥锁合在一起的,条件变量主要是对公共资源的上锁和解锁来进行同步,而信号灯主要是对灯的值进行判断,根据其大于或小于0进行同步操作。

sem_trywait当灯值为0时,并不将调用线程投入休眠,而是返回EAGAIN错误。

5.sem_post

#include<semaphore.h>
int sem_post(sem_t *sem);

当一个线程使用完某个信号灯时,它调用sem_post。使信号灯的数值加1,然户唤醒正在等待信号灯数值变为正数的任意线程

6.sem_getvalue

#include<semaphore.h>
int sem_getvalue(sem_t *sem,int value);

返回所指定信号灯的当前值,如果信号灯当前值以上锁,那么返回或为0,或为某个负数,其绝对值等于该信号灯解锁的线程数。

现在看出了互斥锁、条件变量和信号灯之间的差别。首先:互斥锁必须有给它上锁的线程进行解锁,而信号灯没有这限制。其次,每个信号灯有一个与它相关联的数值,它由挂出函数加1sem_post,由等待函数减1即sem_wait,即使当时没有线程在等待信号灯由0变为正数,该信号灯同样可以挂出该信号灯。而条件变量某个线程调用了pthread_cond_signal,若当时没有线程阻塞在pthread_cond_wait调用中,那么此信号将丢失。

二,实例

1 #include<semaphore.h>
2 #include<unistd.h>
3 #include<stdio.h>
4 #include<stdlib.h>
5 #include<fcntl.h>
6 #include<pthread.h>
7 #include<sys/types.h>
8 #include <sys/syscall.h>
9 #define gettid()(syscall(__NR_gettid ))
10
11 void *thread_function(void*arg);
12 void print(pid_t);
13 sem_t *sem;//deine semaphore
14 int val; //semaphore value
15
16 int main(int argc,char ** argv){
17
18 pthread_t a_thread;
19 int n = 0;
20 if(argc != 2){
21 printf("please input a file name!\n");
22 exit(1);
23 }
24
25 sem = sem_open(argv[1],O_CREAT,0644,3);//open semaphore
26
27 while(n++ < 5){
28 if((pthread_create(&a_thread,NULL,thread_function,NULL)) != 0){
29 printf("Thread create failed\n");
30 exit(1);
31 }
32 }
33
34 pthread_join(a_thread,NULL);
35 sem_close(sem);
36 sem_unlink(argv[1]);
37 }
38
39 void *thread_function(void *arg){
40 sem_wait(sem);
41 pid_t pid;
42 pid = gettid();
43 print(pid);
44 sleep(1);
45 sem_post(sem);
46 printf("I'm finished,my tid is %d\n",pid);
47 }
48
49 void print(pid_t pid){
50 printf("I get it,my tid is %d\n",pid);
51
52 sem_getvalue(sem,&val);
53 printf("Now the value is %d\n",val);
54 }


输出为:
I get it,my tid is 3158
Now the value is 0
I get it,my tid is 3159
Now the value is 0
I get it,my tid is 3160
Now the value is 0
I'm finished,my tid is 3158
I get it,my tid is 3162
Now the value is 1
I'm finished,my tid is 3159
I'm finished,my tid is 3160
I get it,my tid is 3161
Now the value is 1
I'm finished,my tid is 3162


解析:
I get it,my tid is 3158
Now the value is 0
I get it,my tid is 3159
Now the value is 0
I get it,my tid is 3160
Now the value is 0

ID为3158、3159、3160的三各进程首先调用sem_wait将信号灯减1,那么此时的信号灯数值变为0,这就意为着其它进程无法使用信号灯,只有调用sem_wait进入休眠状态,等待信号灯数值变为正数。

I'm finished,my tid is 3158:这时ID为3158的进程调用sem_post将信号灯数值加1,并唤醒处于休眠状态的任意其它进程。

I get it,my tid is 3162:这时ID为3158进程唤醒的,它同样调用sem_wait将信号灯挂起,即将信号灯数值减去1,此时信号灯的数值又变为0.

Now the value is 1:这句是ID为3158进程调用sem_post后将信号灯数值加1之后的输出。

I'm finished,my tid is 3159
I'm finished,my tid is 3160
他们是:ID为3159和3160进程调用sem_post后将信号灯数值加1后的输出,此时信号灯的数值为2,他们将唤醒另外的处于休眠的进程。

I get it,my tid is 3161:此进程被唤醒。

I'm finished,my tid is 3162:ID为3162的进程结束。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值