信号量(sem)

本文介绍了一种利用信号量实现进程间互斥访问的方法。通过创建信号量、初始化信号量值,并结合P/V操作,实现了父子进程对标准输出的互斥访问。代码示例展示了如何在C语言中实现这一机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码:

comm.h:

#ifndef _MYSEM_
#define _MYSEM_
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define _PATH_ "."
#define _PROJ_ID_ 0x0603

typedef 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) */
}semun_t;

int create_sem(int nsems);
int get_sem(int nsems);
int init_sem(int sem_id,int which,int init_val);
int p_sem(int sem_id,unsigned short which);//-1
int v_sem(int sem_id,unsigned short which);//+1
int destroy_sem(int sem_id);

#endif

comm.c:

#include "comm.h"

static int com_sem(int nsems,int flag)
{
	key_t key = ftok(_PATH_,_PROJ_ID_);
	if( key < 0 ){
		perror("ftok");
		return -1;
	}
	int sem_id = semget(key,nsems,flag);//创建信号量
	if(sem_id < 0){
		perror("semget");
		return -2;
	}
	return sem_id;
}
int creat_sem(int nsems)
{
	int flag = IPC_CREAT | IPC_EXCL | 0666;
	return com_sem(nsems,flag);
}
int get_sem(int nsems)
{
	int flag = IPC_CREAT;
	return com_sem(nsems,flag);
}
static int com_semop(int sem_id,unsigned short which,short op)
{//对哪个信号量集中的哪一个信号进行op指定的操作
	struct sembuf semb[1];//只考虑二元信号量,所以只有一个元素
	semb[0].sem_num = which;
	semb[0].sem_op = op;//进行什么操作是由op说了算
	semb[0].sem_flg = 0;//UNDO,若一个进程在临界区崩溃了,那么flag就维护信号量,把信号量恢复
	if(semop(sem_id,semb,1) < 0)
	{
		perror("semop");
		return -1;
	}
	return 0;
}
int p_sem(int sem_id,unsigned short which)
{//进行p操作
	int op = -1;
	return com_semop(sem_id,which,op);
}
int v_sem(int sem_id,unsigned short which)
{//进行v操作
	int op = 1;
	return com_semop(sem_id,which,op);
}
int init_sem(int sem_id,int which,int init_val)
{
	semun_t sem_val;
	sem_val.val = init_val;
	int ret = semctl(sem_id,which,SETVAL,sem_val);//初始化信号量
	if(ret < 0)
	{
		perror("semct");
		return -1;
	}
	return 0;
}
int destory_sem(int sem_id)
{
	int ret = semctl(sem_id,0,IPC_RMID);//0是指定的信号量,此处讨论的是二元信号量
	if(ret < 0){
		perror("semctl");
		return -1;
	}
	printf("\ndestroy success\n");
	return 0;
}
sem_stdout.c:(父子进程互斥访问stdout)

#include "comm.h"

int main()
{
	int f_sem_id = creat_sem(1);//使用互斥信号量(二元信号量)父进程先获取信号量
	init_sem(f_sem_id,0,1);//信号量从下标0开始,被初始化为1
	pid_t id = fork();
	if( id == 0)
	{//child
		int c_sem_id = get_sem(1);
		int count = 3;
		while(1)
		{
			p_sem(c_sem_id,0);//对第一个信号量进行P操作
			printf("A");
			fflush(stdout);
			sleep(rand()%3);
			printf("A");
			fflush(stdout);
			sleep(rand()%3);
			v_sem(c_sem_id,0);//对第一个信号量进行V操作
			count--;
			if(count == 0){
				break;
			}
		}
	}
	else
	{//father
		int count = 3;
		while(1)
		{
			p_sem(f_sem_id,0);
			printf("B");
			fflush(stdout);
			sleep(rand()%3);
			printf("B");
			fflush(stdout);
			sleep(rand()%3);
			v_sem(f_sem_id,0);
			count--;
			if(count == 0){
				break;
			}
		}
	}
	//sleep(3);
	wait(NULL);
	destory_sem(f_sem_id);
	return 0;
}

运行结果:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值