学习IO的第八天

发布时间:2023年12月18日

作业:使用信号灯循环输出ABC

sem.c

#include <head.h>

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


//初始化函数
int init_sem(int semid, int semno)
{
	int val = -1;
	printf("请输入编号为%d的灯的初始值:", semno);
	scanf("%d", &val);
	getchar();     //吸收scanf留下的回车

	//对当前灯进行赋初始值
	//定义一个共用体变量
	union semun us;
	us.val = val;           //要赋的值
	if(semctl(semid, semno, SETVAL, us) == -1)
	{
		perror("semctl error\n");
		return -1;
	}


	//成功返回0
	return 0;
}


//信号灯集的申请,初始化信号灯,并返回信号灯集的id
int create_sem(int semcount)
{
	//1.创建key值
	key_t key = ftok("/", 'y');
	if(key == -1)
	{
		perror("ftok error\n");
		return -1;
	}

	//2.通过key值创建一个信号灯集
	int semid = semget(key, semcount, IPC_CREAT|IPC_EXCL|0664);
	if(semid == -1)
	{
		if(errno == EEXIST)
		{
			//信号灯集已经存在,无需创建直接打开即可
			semid = semget(key, semcount, IPC_CREAT);
			return semid;            //之后的进程打开信号灯集只需返回id即可,无需进行初始化操作
		}

		perror("semget error\n");
		return -1;
	}

	//3.给信号灯集中的信号灯进行初始化操作
	for(int i=0;i<semcount;i++)
	{
		init_sem(semid, i);         //初始化编号为i的灯value值
	}

	//4.返回信号灯集的id
	return semid;
}

//申请信号灯资源操作P操作
int P(int semid, int semno)
{
	//定一个操作的结构体变量
	struct sembuf buf;
	buf.sem_num = semno;      //要操作的灯的编号
	buf.sem_op = -1;          //表示申请资源操作
	buf.sem_flg = 0;          //如果没有资源,则阻塞等待

	//调用semop函数完成P操作
	if(semop(semid, &buf, 1) == -1)
	{
		perror("semop error\n");
		return -1;
	}

	return 0;       //成功返回0
}

//释放信号灯资源操作 v操作
int V(int semid, int semno)
{
	//定一个操作的结构体变量
	struct sembuf buf;
	buf.sem_num = semno;      //要操作的灯的编号
	buf.sem_op = 1;          //表示释放资源操作
	buf.sem_flg = 0;          //如果没有资源,则阻塞等待

	//调用semop函数完成V操作
	if(semop(semid, &buf, 1) == -1)
	{
		perror("semop error\n");
		return -1;
	}

	return 0;       //成功返回0

}

//信号灯集的删除
int del_sem(int semid)
{
	if(semctl(semid, 0, IPC_RMID, 0) == -1)
	{
		perror("del error\n");
		return -1;
	}

	return 0;
}



主函数

#include <head.h>
#include "sem.h"

#define PAGE_SIZE 4096

int main(int argc, const char *argv[])
{
	//创建一个信号灯集
	int semid = create_sem(3);       //创建一个信号灯集包含两个灯,并初始化
	if(semid == -1)
	{
		perror("create_sem error\n");
		return -1;
	}

	//创建的key值
	key_t key = ftok("/", 'y');
	if(key == -1)
	{
		perror("ftok error\n");
		return -1;
	}
	printf("key = %#x\n", key);

	//通过key值创建共享内存段
	int shmid = shmget(key, PAGE_SIZE, IPC_CREAT|0664);
	if(shmid == -1)
	{
		perror("shmget error\n");
		return -1;
	}
	printf("shmid = %d\n", shmid);

	//将共享内存段映射到用户空间
	char *addr = (char *)shmat(shmid, NULL, 0);

	if(addr == (void *)-1)
	{
		perror("shmat error\n");
		return -1;
	}
	printf("addr = %p\n", addr);     //输出映射的虚拟地址

	pid_t pid = -1;
	
	pid = fork();

	if(pid > 0)
	{
		pid_t pid2 = fork();
		if(pid2 > 0)
		{
			//父进程

			int count =0;
			while(1)
			{
				//V操作,释放1灯的资源				
				P(semid,0);
			
				printf("A");
				count++;
				fflush(stdout);    //每个进程的用户空间相互独立,缓冲区不同
				
				V(semid,1);
				if(count == 5)
				{
					break;
				}
			}	
			wait(NULL);
			wait(NULL);
			wait(NULL);
		}
		else if(pid2 == 0)
		{
			//子进程2
			int count=0;
			while(1)
			{
				//P操作,等待0灯的资源
				P(semid, 2);

				printf("C\n");
				count++;
				V(semid, 0);

				if(count == 5)
				{
				break;
				}

			}
			exit(EXIT_SUCCESS);

		}
		else
		{
			perror("fork2 error\n");

			return -1;
		}
	}
	else if(pid == 0)
	{
		//子进程1
		int count=0;
		while(1)
		{
			//P操作,等待1号灯的资源
			P(semid, 1);

			printf("B");
			count++;
			fflush(stdout);
			//V操作,释放0号灯的资源
			V(semid,2);

			if(count == 5)
			{
				break;
			}

		}
		exit(EXIT_SUCCESS);
	}
	else 
	{
		perror("fork1 error\n");
		return -1;
	}

	if(shmdt(addr) == -1)
	{
		perror("shmdt error\n");
		return -1;
	}

	del_sem(semid);

	return 0;
}

现象

文章来源:https://blog.csdn.net/zdy_cl/article/details/134958381
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。