IPC对象之信号量

1. 信号量

1)信号量(semaphore),也叫信号灯。它是不同进程间或一个给定进程内部不同线程间同步的机制。

2)二值信号量:值为0或1。与互斥锁类似,资源可用时值为1,不可用时值为0。

3)计数信号量:值在0到n之间。同来统计资源,其值代表可用资源数。

4)等待操作是等待信号量的值变为大于0,然后将其减一;而释放操作则相反,用来唤醒等待资源的进程或者线程。

 

2. 信号量编程函数

在Linux系统中,使用信号量通常需要创建信号量、初始化信号量、信号量PV操作以及信号量删除四种操作。

 

1)创建信号量

函数semget()

所需头文件:#include<sys/types.h>

                     #include<sys/ipc.h>

                     #include<sys/sem.h>

函数原型:int semget(key_t key, int nsems, intsemflg)

函数参数:

              key         信号量的键值,其他进程通过该值访问该信号量,其中有个特殊值IPC_PRIVATE,表示创建当前进程的私有信号量

              nsems    需要创建的信号量数目,通常为1。若创建多个信号量则称为信号量集

              semflg    同open()函数的第三个参数,为信号量设定权限,通常使用八进制表示。

函数返回值:

              成功:信号量的标识符(非负整数)

              失败:-1

 

2)初始化信号量,函数semctl()用于对信号量进行相应的控制,包括设置初始化值、获取信息、设置属性、删除信号量(集)等操作

函数semctl()

头文件:#include<sys/types.h>

              #include<sys/ipc.h>

              #include<sys/sem.h>

函数原型:int semctl(int semid, int semnum, intcmd, union semun arg)

函数参数:

              semid     信号量标识符(即semget()函数的返回值)

              semnum 信号量编号,通常存在多个信号量时才会使用。通常取值为0,即第一个信号量。

              cmd       需要对信号量采取的操作。可取值有很多,常用的有:

              IPC_STAT       读取消息队列的数据结构semid_ds并将其存储在第四个参数arg结构变量的buf指定的地址中

              IPC_SETVAL   将信号量值设定为arg中的val值

              IPC_GETVAL   获取当前信号量的值

              IPC_RMID      从内核中删除信号量(集)

              arg         是一个union semun结构的共用体,常用类型如下:

                     union semun

                     {

                            int              val;    /* Value for SETVAL */

                            struct semid_ds *buf;    /* Buffer for IPC_STAT,IPC_SET */

                            unsigned short  *array;  /* Array for GETALL, SETALL */

                            struct seminfo  *__buf;  /* Buffer for IPC_INFO

                                          (Linux-specific) */

                     };

                     注意:某些系统内未给出union semun的定义,需要程序员自己定义该共用体。

                     其中buf参数是一个semid_ds类型的结构体指针,使用时必须使用地址传递的方式。结构体成员很多,常用的有:

                     struct  semid_ds

                     {

                            uid_t sem_perm.uid;    /* Effective UID of owner*/

                            gid_t sem_perm.gid;    /* Effective GID of owner*/

                            ……

                     };

                    

函数返回值:成功:

                     IPC_STAT、IPC_SETVAL或IPC_RMID操作:0

                     IPC_GETVAL操作:返回当前信号量的值

                 失败:-1

 

3)信号量PV操作

函数semop()

头文件:#include<sys/types.h>

              #include<sys/ipc.h>

              #include<sys/sem.h>

函数原型:int semop(int semid, struct sembuf*sops, size_t nsops)

函数参数:

              semid     信号量标识符(即semget()函数的返回值)

              sops 是一个sembuf类型的结构体指针,使用时必须使用地址传递的方式。结构体类型如下:

                     struct sembuf

                     {

                            unsigned short sem_num;//信号量编号,若是单个信号量则取值0

                            short sem_op;//取值-1为P操作,取值1为V操作

                            short sem_flg;//通常取值SEM_UNDO,表示进程结束后系统自动释放该进程中未释放的信号量

                     }

              nsops     需要操作的信号量数目,通常取值1(一个操作)

函数返回值:

              成功:信号量的标识符

              失败:-1

 

示例:有两个进程,进程A和进程B,这两个进程通过共享内存通信,进程A负责写内存,进程B负责读内存。要求进程A写一次,然后B读一次。这里用两个信号量进行读写的同步。(在博文:IPC对象之共享内存中使用无名管道进行都写得同步)。

 

方法一程序结构图如下:

示例代码:

 

/*************************************************************************

 @Author: wanghao

 @Created Time : Wed 23 May 2018 07:37:06 PMPDT

 @File Name: sem_demo.c

 @Description:

 ************************************************************************/

#include <sys/shm.h>

#include <sys/sem.h>

#include <string.h>

#include <stdio.h>

#include <stdlib.h>

#include <assert.h>

 

/*The structure that stores the data*/

typedef struct{

       int val;

       int semid;

}Storage;

 

void init(Storage *s)

{

       assert(s!= NULL);

       /*Create semaphore, return semaphore value*/

       if((s->semid= semget(IPC_PRIVATE,2,IPC_CREAT|IPC_EXCL|0777)) <0){

              perror("semgeterror");

              exit(1);

       }

       /*Define union semun struct*/

       union semun{

              int val;

              struct semid_ds *ds;

              unsigned short *array;

       };

       union semun un;

       /*Each value in the semaphore*/

       unsigned short array[2] = {0,1};

       un.array= array;

       /*Set all values in the semaphore*/

       if(semctl(s->semid,0,SETALL,un)<0){

              perror("semctrlerror");

              exit(1);

       }

 

 

}

 

void destroy(Storage *s)

{

       assert(s!= NULL);

       /*Delete semaphore*/

       if(semctl(s->semid,0,IPC_RMID,NULL)<0){

              perror("semctlerror");

              exit(1);

       }

 

 

}

 

void write(Storage *s, int val)

{

       /*Set semaphore 0 to V Operation*/

       struct sembuf ops_v[1] = {{0,1,SEM_UNDO}};


       /*Set semaphore 1 to P Operation*/

       struct sembuf ops_p[1] = {{1,-1,SEM_UNDO}};


       /*Set semaphore 1 to P Operation*/

       if(semop(s->semid,ops_p,1)<0){

              perror("semoperror");

       }

       s->val= val;

       printf("%d write %d\n",getpid(),val);

      

       /*Set semaphore 1 to V Operation*/

       if(semop(s->semid,ops_v,1)<0){

              perror("semoperror");

       }

 

}

 

void read(Storage *s)

{

       assert(s!= NULL);

       /*Setsemaphore 0 to P Operation*/

       struct sembuf ops_p[1] = {{0,-1,SEM_UNDO}};    


       /*Set semaphore 0 to V Operation*/

       struct sembuf ops_v[1] = {{1,1,SEM_UNDO}};

 

       /*Set semaphore 0 to P Operation*/

       if(semop(s->semid,ops_p,1)<0){

              perror("semoperror");

       }

       printf("%d read %d\n",getpid(),s->val);

 

       /*Setsemaphore 0 to V Operation*/

       if(semop(s->semid,ops_v,1)<0 ){

              perror("semoperror");

       }

 

}

 

int main(void)

{

       intshmid;

       /*Create Shared Memory, size is sizeof Storage*/

       if((shmid= shmget(IPC_PRIVATE,sizeof(Storage),

                            IPC_CREAT|IPC_EXCL|0777))< 0){

              perror("shmgeterror");

              exit(1);

       }

       /*Map shared memory*/

       Storage *s = (Storage*) shmat(shmid,0,0);

       if(s== (Storage*) -1){

              perror("shmaterror");

              exit(1);

       }

 

       init(s);

       pid_tpid;

       pid= fork();

       if(pid<0){

              perror("forkerror");

              exit(1);

       }else if(pid > 0){

              inti = 1;

              for(;i<=100; i++){

                     write(s,i);

              }

              wait(NULL);

              /*Deletesemaphore*/

              destroy(s);

              /*Unlocka shared memory map*/

              shmdt(s);

              /*Deletememory*/

              shmctl(shmid,IPC_RMID,NULL);

 

       }else{

              int i = 1;

              for(;i<=100;i++){

                     read(s);

              }

              /*Unlocka shared memory map*/

              shmdt(s);

       }

      

       exit(0);

}

 

方法二程序结构图如下:

 

示例代码如下,与方法1的不同之处,用红笔标出。

/*************************************************************************

 @Author: wanghao

 @Created Time : Wed 23 May 2018 07:42:18 PMPDT

 @File Name: sem_demo1.c

 @Description:

 ************************************************************************/

#include <sys/shm.h>

#include <sys/sem.h>

#include <string.h>

#include <stdio.h>

#include <stdlib.h>

#include <assert.h>

 

/*The structure that stores the data*/

typedef struct{

       intval;

       intsemid;

}Storage;

 

void init(Storage *s)

{

       assert(s!= NULL);

       /*Createsemaphore, return semaphore value*/

       if((s->semid= semget(IPC_PRIVATE,2,IPC_CREAT|IPC_EXCL|0777)) <0){

              perror("semgeterror");

              exit(1);

       }

       /*Defineunion semun struct*/

       unionsemun{

              intval;

              structsemid_ds *ds;

              unsignedshort *array;

       };

       union semun un;

       /*Eachvalue in the semaphore*/

       unsigned short array[2] = {0,0};

       un.array= array;

       /*Setall values in the semaphore*/

       if(semctl(s->semid,0,SETALL,un)<0){

              perror("semctrlerror");

              exit(1);

       }

 

 

}

 

void destroy(Storage *s)

{

       assert(s!= NULL);

       /*Deletesemaphore*/

       if(semctl(s->semid,0,IPC_RMID,NULL)<0){

              perror("semctlerror");

              exit(1);

       }

 

 

}

 

void write(Storage *s, int val)

{

       /*Set semaphore 0 to V Operation*/

       struct sembuf ops_v[1] = {{0,1,SEM_UNDO}};

       /*Set semaphore 1 to P Operation*/

       struct sembuf ops_p[1] = {{1,-1,SEM_UNDO}};

       s->val = val;

       printf("%d write %d\n",getpid(),val);

      

       /*Set semaphore 1 to V Operation*/

       if(semop(s->semid,ops_v,1) <0){

              perror("semop error");

       }

 

       /*Set semaphore 1 to P Operation*/

       if(semop(s->semid,ops_p,1)<0){

              perror("semop error");

       }

 

}

 

void read(Storage *s)

{

       assert(s!= NULL);

       /*Setsemaphore 0 to P Operation*/

       structsembuf ops_p[1] = {{0,-1,SEM_UNDO}};

       /*Setsemaphore 0 to V Operation*/

       structsembuf ops_v[1] = {{1,1,SEM_UNDO}};

 

       /*Setsemaphore 0 to P Operation*/

       if(semop(s->semid,ops_p,1)<0){

              perror("semoperror");

       }

       printf("%dread %d\n",getpid(),s->val);

 

       /*Setsemaphore 0 to V Operation*/

       if(semop(s->semid,ops_v,1)<0 ){

              perror("semoperror");

       }

 

}

 

int main(void)

{

       intshmid;

       /*CreateShared Memory, size is sizeof Storage*/

       if((shmid= shmget(IPC_PRIVATE,sizeof(Storage),

                            IPC_CREAT|IPC_EXCL|0777))< 0){

              perror("shmgeterror");

              exit(1);

       }

       /*Mapshared memory*/

       Storage*s = (Storage*) shmat(shmid,0,0);

       if(s== (Storage*) -1){

              perror("shmaterror");

              exit(1);

       }

 

       init(s);

       pid_tpid;

       pid= fork();

       if(pid<0){

              perror("forkerror");

              exit(1);

       }elseif(pid > 0){

              inti = 1;

              for(;i<=100; i++){

                     write(s,i);

              }

              wait(NULL);

              /*Deletesemaphore*/

              destroy(s);

              /*Unlocka shared memory map*/

              shmdt(s);

              /*Deletememory*/

              shmctl(shmid,IPC_RMID,NULL);

 

       }else{

              inti = 1;

              for(;i<=100;i++){

                     read(s);

              }

              /*Unlocka shared memory map*/

              shmdt(s);

       }

      

       exit(0);

}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值