进程通信 二、XSI进程间通信之信号量

内核维护的计数器,用于管理多进程之间共享资源。

例如:有个变量n表示资源的数量,当有个进程想要独占一个资源时,n的值要减1(可能减多个),如果n的值等于0(不够减),则进程阻塞,直到n的值可以减会被再次唤醒,当资源使用完毕后n要加1(可能加多个)。

用到的函数:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

Int  semget(key_t  key, int  nsems, int  semflg);

功能:创建/获取信号量

key:        IPC键值,由ftok函数生成

nsems:信号量的数量

semflg:

0        

获取信号量

IPC_CREAT

创建信号量(存在则获取,不存在则创建)

IPC_EXCL        

如果已经存在则创建失败

返回值:信号量标识

 

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

功能:操作信号量(对信号量进行加减操作)

semid:信号量标识,semget的返回值

sops:结构体数组

struct sembuf

{

unsigned short sem_num;  信号量的下标        /* semaphore number */

short          sem_op;   操作                        /* semaphore operation */

short          sem_flg;  标记:                        /* operation flags */

sem_flg:

IPC_NOWAIT :信号量不够减的时候不阻塞

SEM_UNDO        :当进程结束时,信号量的值自动归还        

}

nsops:数组的长度

 

Int  semtimedop(int  semid, struct sembuf  *sops, unsigned  nsops, struct timespec  *timeout);

功能:带时间限制的操作信号量  

struct timespec

{

__time_t tv_sec;         秒

long int tv_nsec;        纳秒

 

}

 

Int  semctl(int  semid, int  semnum, int  cmd,  ...);

功能:初始化信号量的值/删除信号量/获取、设置信号量的属性

cmd:

IPC_STAT:获取信号量的属性

IPC_SET:设置信号量的属性

struct ipc_perm

{

key_t          __key; /* Key supplied to semget(2) */

uid_t          uid;   /* Effective UID of owner */

gid_t          gid;   /* Effective GID of owner */

uid_t          cuid;  /* Effective UID of creator */

gid_t          cgid;  /* Effective GID of creator */

unsigned short mode;  /* Permissions */

unsigned short __seq; /* Sequence number */

};

IPC_RMID        :删除信号量

IPC_INFO        :获取信号量的信息

struct  seminfo

 {

                         int semmap;  /* Number of entries in semaphore map; unused within kernel */

                         int semmni;  /* Maximum number of semaphore sets */

                         int semmns;  /* Maximum number of semaphores in all semaphore sets */

                         int semmnu;  /* System-wide maximum number of undo structures; unused within kernel */

                         int semmsl;  /* Maximum number of semaphores in a set */

                         int semopm;  /* Maximum number of operations for semop(2) */

                         int semume;  /* Maximum number of undo entries perprocess; unused within kernel */

                         int semusz;  /* Size of struct sem_undo */

                         int semvmx;  /* Maximum semaphore value */

                         int semaem;  /* Max. value that can be recorded forsemaphore adjustment (SEM_UNDO) */

                     };

 

SEM_INFO        :设置信号量的信息

GETALL        :获取所有信号量的值

GETNCNT        :获取信号量的数量

GETVAL        :获取某个信号量的值

SETALL        :设置所有信号量的值

SETVAL        :设置某个信号量的值

 

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) */

};

 

***编程模型***

进程A                                

                        进程B

创建信号量                        semget

                        获取信号量

初始化型号量的值              semctl

                        ...

加减信号量                        semop

                        加减信号量

删除信号量                        semctl

                        ...

注意:信号量是用来计数的,一定要与资源对应。

实现代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/wait.h>


int main()
{
	//1.创建信号量
	int semid = semget(ftok(".",888),1,IPC_CREAT|0644);
	if(0 > semid)
	{
		perror("semget");
		return -1;
	}
	//2. 初始化信号量
	if(semctl(semid,0,SETVAL,5))
	{
		perror("semctl");
		return -1;
	}
	printf("我有5个信号\n");
	//3. 创建进程,子进程使用信号量
	for(int i = 0 ; i  < 10 ; i++)
	{
		if(0 == fork())	
		{
			//4.使用信号量
			struct sembuf buf = {0,-1,0};
			semop(semid,&buf,1);
			printf("进程:%u,获得1个信号,还剩%d个信号\n",getpid(),semctl(semid,0,GETVAL));
			printf("-------------------------------------------\n");
			sleep(2);
			//5. 归还信号量
			buf.sem_op = 1;
			semop(semid,&buf,1);
			printf("进程:%u,归还1个信号,还剩%d个信号\n",getpid(),semctl(semid,0,GETVAL));
			exit(0);
		}
	}
	//删除信号量
	while(-1 != wait(NULL))
	{
		printf("回收子进程\n");	
	}
	semctl(semid,0,IPC_RMID);
	return 0;	
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值