Linux 基本语句_14_信号灯实验

原理:

Send进程通过建立共享内存区域,并向其中写入数据,Recive通过与共享内存连接读取其中的数据。
但是如果进程进行读取操作的时候其他进程再次写入会产生数据丢失,产生竞态,为了确保在某段时间内只有一个操作,即读操作或者写操作,所以引入同步互斥机制,对每个信号量的操作为PV操作。

代码:

SemaphoreSend.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/sem.h>
#include <string.h>

#define N 128

struct shmbuf{
   
	char buf[N];
};

union semun{
   
	int val;
};

int main(){
   
	key_t key;
	
	if((key = ftok(".", 'q')) < 0){
    // 创建标识符 
		perror("ftok error");
		return -1;
	}
	
	int shmid;
	struct shmbuf *shm;
	
	if((shmid = shmget(key, 512, IPC_CREAT|IPC_EXCL|0664)) < 0){
    // 创建一块虚拟内存 
		if(errno != EEXIST){
   
			perror("shmget error");
			return -1;
		}
		else{
   
			shmid = shmget(key, 512, 0664);
		} 
	}
	
	if((shm = shmat(shmid, NULL, 0)) > 0){
    //在进程虚拟地址空间选择一块做共享内存,此区域可读可写 
		printf("shm:%p\n", shm); 
	}
	
	int semid;
	union semun semun;
	
	struct sembuf sem;
	semid  = semget(key, 2, IPC_CREAT|IPC_EXCL|0664); // 创建信号量集合,内部设置两个信号量 
	
	if(semid < 0){
    // 创建错误要么有问题要么集合已经存在 
		if(errno != EEXIST){
   
			perror("semget error");
			return -1;
		}
		else{
   
			semid = semget(key, 2, 0664);
		}
	}
	else{
    // 初始化信号量的值 
		semun.val = 0;
		semctl(semid, 0, SETVAL, semun); // 设置第一个信号量的值为0
		semun.val = 1;
		semctl(semid, 1, SETVAL, semun); // 设置第二个信号量的值为1 
	}
	
	while(1){
   
		sem.sem_num = 1;
		sem.sem_op = -1; 
		sem.sem_flg = 0;  
		semop(semid, &sem, 1); // 获取写权限 
		
		fgets(shm->buf, N, stdin); // 向控制台获取数据写入共享内存,且指针指向用户输入 
		shm->buf[strlen(shm->buf) - 1] = '\0'; // 将换行符号变成'\0'
		
		sem.sem_num = 0;
		sem.sem_op = 1;
		sem.sem_flg = 0; // 释放读权限 
		semop(semid, &sem, 1);
		
		if(strncmp(shm->buf, "quit", 4) == 0){
   
			shmdt(shm); // 断开虚拟内存 
			break;
		} 
	} 
	
	return 0;
}

SemaphoreRecive.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/sem.h>
#include <string.h>

#define N 128

struct shmbuf{
   
	char buf[N];
};

union semun{
   
	int val;
};

int main(){
   
	key_t key;
	
	if((key = ftok(".", 'q')) < 0){
    // 创建标识符 
		perror("ftok error");
		return -1;
	}
	
	int shmid;
	struct shmbuf *shm;
	
	if((shmid = shmget(key, 512, IPC_CREAT|IPC_EXCL|0664)) < 0){
    // 创建一块虚拟内存 
		if(errno != EEXIST){
   
			perror("shmget error");
			return -1;
		}
		else{
   
			shmid = shmget(key, 512, 0664);
		} 
	}
	
	if((shm = shmat(shmid, NULL, 0)) > 0){
    //在进程虚拟地址空间选择一块做共享内存,此区域可读可写 
		printf("shm:%p\n", shm); 
	}
	
	int semid;
	union semun semun;
	
	struct sembuf sem;
	semid  = semget(key, 2, IPC_CREAT|IPC_EXCL|0664); // 创建信号量集合,内部设置两个信号量 
	
	if(semid < 0){
    // 创建错误要么有问题要么集合已经存在 
		if(errno != EEXIST){
   
			perror("semget error");
			return -1;
		}
		else{
   
			semid = semget(key, 2, 0664);
		}
	}
	else{
    // 初始化信号量的值 
		semun.val = 0;
		semctl(semid, 0, SETVAL, semun); // 设置第一个信号量的值为0
		semun.val = 1;
		semctl(semid, 1, SETVAL, semun); // 设置第二个信号量的值为1 
	}
	
	while(1){
   
		sem.sem_num = 0;
		sem.sem_op = -1; 
		sem.sem_flg = 0; // 申请读权限 
		semop(semid, &sem, 1); 
		
		if(strncmp(shm->buf, "quit", 4) == 0){
   
			shmdt(shm); // 断开共享内存
			shmctl(shmid, IPC_RMID, NULL); // 删除共享内存断 
			semctl(semid, 0, IPC_RMID, NULL);
			semctl(semid, 1, IPC_RMID< NULL); // 删除信号量,删除信号集 
			break;
		}
		
		printf("buf:%s\n", shm->buf); 
		
		sem.sem_num = 1;
		sem.sem_op = 1;
		sem.sem_flg = 0; // 释放写权限 
		semop(semid, &sem, 1);
		
 
	} 
	
	return 0;
}

开启两个端口,分别运行Send和Recive程序

效果:

在这里插入图片描述

相关推荐

  1. LinuxC语言信号基本概念与基本使用

    2023-12-07 14:18:06       14 阅读
  2. linux实验一,练习基础语法

    2023-12-07 14:18:06       18 阅读
  3. Linux信号基础

    2023-12-07 14:18:06       4 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-07 14:18:06       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-07 14:18:06       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-07 14:18:06       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-07 14:18:06       20 阅读

热门阅读

  1. 数据分析NumPy

    2023-12-07 14:18:06       38 阅读
  2. TCP 连接建立

    2023-12-07 14:18:06       32 阅读
  3. 支持向量机(SVM)

    2023-12-07 14:18:06       31 阅读
  4. js优化技巧

    2023-12-07 14:18:06       37 阅读
  5. 数据库系统原理【练习题】——第一章:概述

    2023-12-07 14:18:06       33 阅读
  6. Vue3中teleport如何使用

    2023-12-07 14:18:06       29 阅读
  7. nodejs + vue + element 本地调用七牛上传图片

    2023-12-07 14:18:06       37 阅读
  8. VUE实现纵向动态表格

    2023-12-07 14:18:06       41 阅读