IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 进程间通信(十四)——信号量编程应用:对共享内存的同步访问 -> 正文阅读

[系统运维]进程间通信(十四)——信号量编程应用:对共享内存的同步访问

信号量编程应用:对共享内存的同步访问

system V 信号量编程应用

  • 对共享内存的同步访问
    • 通过读写信号量实现对共享内存的同步互斥访问
    • 实现一个二元信号量协议
      • 读信号量:当为1时,读进程才能进行P操作、读取数据,否则会阻塞
      • 写信号量:当为1时,写进程才能进行p操作、写入数据,否则会阻塞
  • int semctl(int semid, int semnum, int cmd, ...);

semctl函数对一个信号量执行各种控制操作。

semctl() 在?semid?标识的信号量集上,或者该集合的第semnum?个信号量上执行?cmd?指定的控制命令。(信号量集合索引起始于零。)

根据?cmd?不同,这个函数有三个或四个参数

当有四个参数时,第四个参数的类型是?union semun?。调用程序?必须按照下面方式定义这个联合体:

union semun {?
? ? ?   ?int              val; ? ?  // SETVAL使用的值 ??

? ? ? ? ?struct semid_ds *buf;    ? // IPC_STAT、IPC_SET 使用缓存区

? ? ? ? ?unsigned short  *array;    // GETALL,、SETALL 使用的数组?

? ? ? ? ?struct seminfo  *__buf;    // IPC_INFO(Linux特有) 使用缓存区?

};
union semun {?

? ? ? **? ?int              val; ? ? ? ? ? ? ?  // SETVAL使用的值 ??**

? ? ? ? ?struct semid_ds *buf;    ? // IPC_STAT、IPC_SET 使用缓存区

? ? ? ? ?unsigned short  *array;   // GETALL,、SETALL 使用的数组?

? ? ? ? ?struct seminfo  *__buf;    // IPC_INFO(Linux特有) 使用缓存区?

};

注意:该联合体没有定义在任何系统头文件中,因此得用户自己声明。


semid_ds 数据结构在头文件 <sys/sem.h> 有如下定义:

struct semid_ds {?

? ? ? ?struct ipc_perm sem_perm; ?     // 所有者和权限

? ? ? ?time_t                sem_otime; ? ?? // 上次执行 semop 的时间 ?

? ? ? ?time_t                sem_ctime; ? ?  // 上次更新时间?

? ? ? ?unsigned short  sem_nsems;  ? // 在信号量集合里的索引

?};


结构体 ipc_perm 在头文件 <sys/ipc.h>
中的定义如下(高亮的字段可以使用 IPC_SET 设置):

struct ipc_perm {?

? ? ? ?key_t          __key; ? ?// 提供给 semget()的键?

? ? ? ?uid_t          uid; ? ? ?// 所有者有效 UID ?

? ? ? ?gid_t          gid; ? ? ?// 所有者有效 GID?

? ? ? ?uid_t          cuid; ? ? // 创建者有效 UID?

? ? ? ?gid_t          cgid; ? ? // 创建者有效 GID

? ? ? ?unsigned short mode; ? ? // 权限?

? ? ? ?unsigned short __seq; ? ?// 序列号

};

cmd 的有效值是:

IPC_STAT从关联于?semid?的内核数据结构复制数据到?arg.buf?指向的semid_ds* 数据结构。参数?semnum?被忽略。调用进程必须在保量集合里有读权限。

IPC_SET把?arg.buf?指向的?semid_ds?结构的一个成员值写入相关于该信号量集合内核结构,同时更新?sem_ctime?成员。结构中下列成员被更新:sem_perm.uid?、sem_perm.gid?以及sem_perm.mode* (低端 9位)。调用进程的有效用户ID必须匹配信号量集合的所有者(sem_perm.uid?)或创建者(sem_perm.cuid?),或者调用者必须有特权。参数semnum?被忽略。

IPC_RMID立即删除信号量集合,唤醒所有因调用semop() 阻塞在该信号量集合里的所有进程(相应调用会返回错误且?errno?被设置为 EIDRM)。调用进程的有效用户ID必须匹配信号量集合的创建者或所有者,或者调用者必须有特权。参数semnum 被忽略。

IPC_INFO?(Linux 定义的)通过?arg.buf?指向的结构返回系统范围内的信号量限制和参数。这个结构的类型是seminfo*,如果宏 _GNU_SOURCE 特性宏被定义,则该结构定义在头文件<sys/sem.h> 。

struct  seminfo {?

? ? ?int semmap;    // 信号量映射里的条数,内核未使用?

? ? ?int semmni;     // 信号量集合的最大个数?

? ? ?int semmns;    // 在所有信号量集合里信号量个数上限 ?

? ? ?int semmnu;   // 系统范围内的 undo 结构最大个数,内核未使用?

? ? ?int semmsl;     // 一个信号量集合里信号量个数上限?

? ? ?int semopm;   // 执行的最大操作个数 ?

? ? ?int semume;   // 每个进程内 undo 结构最大个数,内核未使用

? ? ?int semusz;    // 结构 sem_undo 的尺寸?

? ? ?int semvmx;   // 信号量值的上限

? ? ?int semaem;  // Max. value that can be recorded for semaphore adjustment (SEM_UNDO)?

};

P:-1 V:+1

write.c

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.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 */
};

int sem_id;

void sem_init(int semid, int nsignum, int sem_value)
{
	union semun sem_union;
	sem_union.val = sem_value;
	if (semctl(semid, nsignum, SETVAL, sem_union) == -1)
	{
		perror("semctl");
		exit(EXIT_FAILURE);
	}
}
/* P:-1 */
void sem_p(int semid, int nsignum)
{
	struct sembuf sops;
	sops.sem_num = nsignum;
	sops.sem_op  = -1;
	sops.sem_flg = SEM_UNDO;
	if (semop(semid, &sops, 1) == -1)
	{
		perror("semop");
		exit(EXIT_FAILURE);
	}
}

/* V:+1 */
void sem_v(int semid, int nsignum)
{
	 struct sembuf sops;   
	 sops.sem_num = nsignum; 
	 sops.sem_op  = 1;
	 sops.sem_flg = SEM_UNDO; 
	 if (semop(semid, &sops, 1) == -1) 
	 {
	 	perror("semop");  
	 	exit(EXIT_FAILURE);     
	 }	 
}

void sem_print(int semid, int nsignum)
{
	int sem_value;
	sem_value = semctl(semid, nsignum, GETVAL);
	printf("sem[%d] = %d\n", nsignum, sem_value);
}

int main(int argc, char *argv[])
{
    int shm_id;
	key_t shm_key = ftok("./", 5151);
	key_t sem_key = ftok("./", 5152);

	shm_id = shmget(shm_key, 1028, IPC_CREAT|0644);
	char *shm_addr = shmat(shm_id, NULL, 0);

	sem_id = semget(sem_key, 2, IPC_CREAT|0664);
	if (sem_id == -1)
	{
		sem_id = semget(sem_key, 2, 0664);
	}
	else
	{
		sem_init(sem_id, 0, 0); //sem[0]:for read
		sem_init(sem_id, 1, 1); //sem[1]:for write
	}

	while(1) //write
	{
		sem_p(sem_id, 1);
		fgets(shm_addr, 1024, stdin);
		sem_v(sem_id, 0);
	}

	return 0;
}

read.c

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>

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

int sem_id;

void sem_init(int semid, int nsignum, int sem_value)
{
	union semun sem_union;
	sem_union.val = sem_value;
	if (semctl(semid, nsignum, SETVAL, sem_union) == -1)
	{
		perror("semctl");
		exit(EXIT_FAILURE);
	}
}
/* P : -1 */
void sem_p(int semid, int nsignum)
{
	struct sembuf sops;
	sops.sem_num = nsignum;
	sops.sem_op  = -1;
	sops.sem_flg= SEM_UNDO;
	if (semop(semid, &sops, 1) == -1)
	{
		perror("semop");
		exit(EXIT_FAILURE);
	}
}

/* V : +1 */
void sem_v(int semid, int nsignum)
{
	struct sembuf sops;
	sops.sem_num = nsignum;
	sops.sem_op  = 1;
    sops.sem_flg = SEM_UNDO;
	if (semop(semid, &sops, 1) == -1)
	{
		 perror("semop");   
		 exit(EXIT_FAILURE);
	}
}

void sem_print(int semid, int nsignum)   
{
	int sem_value;  
	sem_value = semctl(semid, nsignum, GETVAL);
	printf("sem[%d] = %d\n", nsignum, sem_value); 
}

int main(int argc, char *argv[])
{
	int shm_id;
	key_t shm_key = ftok("./", 5151);
	key_t sem_key = ftok("./", 5152);

	shm_id = shmget(shm_key, 1024, IPC_CREAT|0664);
	char *shm_addr = shmat(shm_id, NULL, 0);

	sem_id = semget(sem_key, 2, IPC_CREAT|0644);
	if (sem_id == -1)
	{
		perror("semget");
		exit(EXIT_FAILURE);
	}
	else
	{
		sem_init(sem_id, 0, 0); //sem[0]: For read
		sem_init(sem_id, 1, 1); //sem[1]: For write
	}
	while(1)
	{
		sem_p(sem_id, 0);
		printf("%s\n", shm_addr);
		sem_v(sem_id, 1);
	}

	return 0;
}
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-03-17 22:37:43  更:2022-03-17 22:40:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 1:32:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码