Linux下的信号量

linux下的信号量本身就是临界资源,所以PV操作都是原子操作。

下面是实现二元信号量的代码,二元信号量就是互斥锁。

信号量代码中的semop函数是进行PV操作的核心函数,semop的函数原型为:

                        int semop (int semid, struct sembuf* sops, unsigned nsops);

第一个参数semid为获得的信号量集标识符,第二个参数是一个指向定义的结构体的指针,第三个参数是信号量的个数。

semid由semget获得;

定义的结构体为:

struct sembuf

{

unsigned short sem_num; /* semaphore number */   sem_num是将信号量集视为一个数组的数组下标,第一个信                                                     号量下标为0

short sem_op; /* semaphore operation */          op决定是P操作还是V操作,P操作为-1(信号量-1),V操                                                     作为1(信号量+1)

short sem_flg; /* operation flags */             flags有多个选项

};

flags:

IPC_NOWAIT //对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息。

SEM_UNDO //程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。

如果父进程在进行了P操作后异常退出,SEM_UNDO可以保证子进程不用一直等待父进程的V操作,避免死锁。

       0 // 缺省

在二元信号量中我们一般将flags设为SEM_UNDO,防止出现死锁问题。

comm.h

  1 #ifndef _COMM_H_
  2 #define _COMM_H_
  3 
  4 #include<stdio.h>
  5 #include<sys/types.h>
  6 #include<sys/ipc.h>
  7 #include<sys/sem.h>
  8 #include<stdlib.h>
  9 
 10 #define PATHNAME "."
 11 #define PROJ_ID 0x6666
 12 
 13 int creat(int nums);
 14 int get(int nums);
 15 int destory(int semid);
 16 int init(int semid,int nums,int initval);
 17 int P(int semid,int which);
 18 int V(int semid,int which);
 19 union semun{
 20     int val;
 21     struct semid_ds *buf;
 22     unsigned short *arrary;
 23     struct semiofo *_buf;
 24 };
 25 
 26 #endif

comm.c

  1 #include"comm.h"
  2 
  3 
  4 static int com(int nums,int flags)
  5 {
  6     key_t key=ftok(PATHNAME,PROJ_ID);
  7     if(key<0)
  8         {
  9             perror("ftok");
 10             return -1;
 11         }
 12     int semid=semget(key,nums,flags);
 13     if(semid<0)
 14     {
 15         perror("semid");
 16         return -2;
 17     }
 18     return semid;
 19 }
 20 
 21 int creat(int nums)
 22 {
 23     return com( nums,IPC_CREAT|IPC_EXCL|0666);
 24 }
 25 
 26 int get(int nums)
 27 {
 28     return com(nums,IPC_CREAT);
 29 }
 30 
 31 int destory(int semid)
 32 {
 33     if(semctl(semid,0,IPC_RMID)<0)
 34     {
 35         perror("semctl");
 36         return -1;
 37     }
 38     return 0;
 39 }
 40 
 41 int init(int semid,int nums,int initval)
 42 {
 43     union semun un;
 44     un.val=initval;
 45     if(semctl(semid,nums,SETVAL,un)<0)
 46         {
 47             perror("semctl");
 48             return -1;
 49         }
 50     return 0;
 51 }
 52 
 53 static int sempv(int semid,int which,int op)
 54 {
 55     struct sembuf _sf;
 56     _sf.sem_num=which;
 57     _sf.sem_op=op;
 57     _sf.sem_op=op;
 58     _sf.sem_flg=SEM_UNDO;
 59     if(semop(semid,&_sf,1)<0)
 60         {
 61             perror("semop");
 62             return -1;
 63         }
 64     return 0;
 65 }
 66 
 67 int P(int semid,int which)
 68 {
 69     return sempv(semid,which,-1);
 70 }
 71 int V(int semid,int which)
 72 {
 73     return sempv(semid,which,1);
 74 }


sem.c

  1 #include"comm.h"
  2 
  3 int main()
  4 {
  5     int semid=creat(1);
  6     init(semid,0,1);
  7     pid_t id=fork();
  8     if(id==0)
  9     {//child
 10         int _semid=get(0);
 11         while(1)
 12         {
 13             P(_semid,0);
 14             printf("A");
 15             fflush(stdout);
 16             usleep(300000);
 17             printf("A");
 18             fflush(stdout);
 19             usleep(623456);
 20             V(_semid,0);
 21         }
 22     }   else
 23         {//father                 //我们选择让AB成对出现,保证每个进程都有PV操作
 24             while(1)
 25             {
 26                 P(semid,0);
 27                 usleep(100000);
 28                 printf("B");
 29                 fflush(stdout);
 30                 usleep(400000);
 31                 printf("B");
 32                 fflush(stdout);
 33                 usleep(200000);
 34                 V(semid,0);
 35             }
 36             pid_t ret=waitpid(id,NULL,0);
 37             if(ret<0)
 38             {
 39                 printf("wait success!\n");
 40             }
 41     }
 42     return 0;
 43 }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值