浅析Posix信号灯

Posix信号灯


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

一 有名信号灯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的进程结束。

你可能感兴趣的:(OS)