进程间通信之信号量(三)

信号量
信号量是记录和统计临界资源数目的计数器;
(一)创建信号量:
信号量的申请是以信号量集为单位的;
int semget(key_t key,int nsems,int semflag);
返回值:信号量集的标识符;
参数:
key:用key_t ftok(const char* pathname,int proj_id)来获取;
nsems:表示要创建的这个信号量集中信号量的个数;
semflag:(1)IPC_CREAT:创建这个信号量集,若没有就创建,若有则打开即可;
              (2)IPC_CREAT | IPC_EXCL:若创建的信号量不存在,则:创建;若创建的信号量存在,则:错误返回;
(二)初始化信号量
int semctl(int semid,int semnum, int cmd,);
返回值:(1)返回值为0表示初始化成功;
             (2)初始化失败,返回-1;
参数:
semid:要初始化的信号量所在的信号量集的id;
semnum:要初始化的信号量是该信号量集的第几个信号(从0开始);
cmd:设为SETVAL表示对信号量进行初始化;
(三)删除信号量
int semctl(int semid,int semnum,int cmd)
返回值:(1)返回值为0表示删除信号量成功;
              (2)返回值为-1表示删除失败;
参数:
semid:要删除的信号量集的id;
semnum:设置为0;
cmd:设置为IPC_RMID表示删除操作;
(四)P操作
int semop(int semid,struct sembuf*sops,unsigned nsops)
返回值:(1)返回值为0,表示操作成功;
              (2)返回值为-1,表示操作成功;
参数
semid:为操作的信号量所处的信号量集的id;
sops:所操作的信号量所在的数组;
struct sembuf
{
   unsigned short sem_num;  //操作信号量集中的哪一个信号量
   short sem_op;         //对于信号量执行什么操作
   short sem_flg;
}
sops.sem_op = -1,位P操作;
nsops:操作的信号量的数目;
(五)V操作
int semop(int semid,struct sembuf*sops,unsigned nsops)
返回值:(1)返回值为0,表示操作成功;
              (2)返回值为-1,表示操作失败;
参数:semid:为操作的信号量所处的信号量集的id;
          sops:所操作的信号量所在的数组;
          sops.sem_op = 1,位V操作;
          nsops:操作的信号量的数目
common.h
#ifndef _COMMON_H_
#define _COMMON_H_

#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#define PATHNAME "/home/cm/code"
#define PROJ_ID 0x6666

union semun
{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *_buf;
};

int Creat_Sem();
int Get_Sem();
int Init_Sem(int sem_id,int val);
int Destory_Sem(int sem_id);
int P(int sem_id,int who);
int V(int sem_id,int who);
#endif


common.c
#include"common.h"
static int CommonCreat_Sem(int flags)
{
    key_t key = ftok(PATHNAME,PROJ_ID);
    int sem_id =0;
    if(key<0)
    {
        perror("ftok");
        return -1;
    }
    else
    {
        sem_id = semget(key,1,flags);
        if(sem_id < 0)
        {
            perror("semget");
            return -2;
        }

    }
    return sem_id;
}
int Creat_Sem()
{
    int sem_id = CommonCreat_Sem(IPC_CREAT | IPC_EXCL | 0666);
    return sem_id;
}
int Get_Sem()
{
    int sem_id = CommonCreat_Sem(IPC_CREAT);
    return sem_id;
}

int Init_Sem(int sem_id,int Val)
{
    union semun _un;
    _un.val = Val;
    int ret = semctl(sem_id,0,SETVAL,_un);
    if(ret < 0)     //init failed
    {
        perror("semctl");
        return -1;
    }
    return 0;  //init success
}

int Destory_Sem(int sem_id)
{
    int ret = semctl(sem_id,0,IPC_RMID);
    if(ret < 0)
    {
        perror("semctl");
        return -1;
    }
    return 1;
}

static int CommonPV(int sem_id,int who,int op)
{
    struct sembuf _sf;
    _sf.sem_num = who;
    _sf.sem_op = op; //P:-1;V:1
    _sf.sem_flg = 0;
    int ret = semop(sem_id,&_sf,1);
    if(ret<0)
    {
        perror("semop");
        return -1;
    }
    return 0;
}
int P(int sem_id,int who)
{
    return CommonPV(sem_id,who,-1);
}

int V(int sem_id,int who)
{
    return CommonPV(sem_id,who,1);
}



Makefile
test:test_sem.c common.c
    gcc -o $@ $^

.PHONY:clean
clean:
    rm -f test


test_sem.c
#include"common.h"
int main()
{
	int sem_id = Creat_Sem();
	int val = 1;
	Init_Sem(sem_id,val);
	int pid = fork();
	if(pid == 0)
	{
	  //child
	  while(1)
	  {
		P(sem_id,0);
		printf("A");
		fflush(stdout);
		usleep(123456);
		printf("A");
		fflush(stdout);
		usleep(123456);
		V(sem_id,0);
	  }
	}
	else
	{
		while(1)
		{
		    P(sem_id,0);
			printf("B");
			fflush(stdout);
			usleep(123456);
			printf("B");
			fflush(stdout);
			V(sem_id,0);
		}
		wait(NULL);
	}
    printf("\n");
    Destory_Sem(sem_id);
    return 0;
}

注;
struct sembuf
{
   unsigned short sem_num;  //操作信号量集中的哪一个信号量
   short sem_op;         //对于信号量执行什么操作
   short sem_flg;
}
sem_flg:

sem_flg是用来说明semop的操作方式;

(1)IPC_NOWAIT:对信号的操作不成功时,semop不会阻塞,并且立即返回。 

(2)SEM_UNDO:程序结束的时候,对于数据进行回滚,避免造成数据的二义性;

    对于二元信号量来说,为了防止造成死锁问题,必须在程序退出时,对于数据进行回滚,防止造成二义性;产生结果的不确定性;





作者水平有限,若有问题,请留言,谢谢!!!


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值