Linux下用信号量实现对共享内存的访问保护
转自:http://www.cppblog.com/zjl-1026-2001/archive/2010/03/03/108768.html
最近一直在研究多进程间通过共享内存来实现通信的事情,以便高效率地实现对同一数据的访问。本文中对共享内存的实现采用了系统V的机制,我们的重点在于通过信号量来完成对不同进程间共享内存资源的一致性访问,共享内存的具体方法请参见相关资料,这里不再赘述。
首先我们先实现最简单的共享内存,一个进程对其更新,另一个进程从中读出数据。同时,通过信号量的PV操作来达到对共享内存资源的保护。思路如下:
1.server端首先建立一块共享内存的映射,然后创建一个信号量。通过信号量获得对共享资源的使用权限,更新内存中的内容,等待客户端读进程读取共享资源中的数据后,释放共享内存和信号量,然后退出。
2.client端获得对server端创建的共享内存的映射,以及信号量的映射,通过信号量获得对共享资源的访问权限,然后读取其内容,接着解除与共享内存的映射后退出。客户端每次读取共享内存数据时首先调用wait_v()检测信号量的值,当信号量值为0时才能读取共享内存数据然后进行打印。
先来看下程序,然后再对其中的一些API做相关的使用说明。
server端源码
/*编译命令:gcc -o shm shm.c -g */ #include<sys/sem.h>
#include<sys/ipc.h> #define SEGSIZE 1024
#define READTIME 1 9union semum
{
int val;
struct semid_ds *buf;
unsigned short *array;
}arg; /* 创建信号量 */int sem_creat(key_t key)
{
union semun sem;
int semid;
sem.val = ;
semid = semget(key, , IPC_CREAT | ); if (semid == -)
{
printf("Create semaphore error\n");
exit(-);
} semctl(semid, , SETVAL, sem); return semid;
} /* 删除信号量*/int del_sem(int semid)
{
union semun sem;
sem.val = ;
semctl(semid, , IPC_RMID, sem);
} /* 信号量的P操作,使得信号量的值加1 */int p(int semid)
{
struct sembuf sops = {,
+,
IPC_NOWAIT
}; return (semop(semid, &sops, ));
} /* 信号量的v操作,使得信号量的值减1 */int v(int semid)
{
struct sembuf sops = {,
-,
IPC_NOWAIT
}; return (semop(semid, &sops, ));
} /* server主程序 */int main(int argc, char **argv)
{
key_t key;
int shmid, semid;
char *shm;
char msg[] = "-data-";
char i;
struct semid_ds buf; key = ftok("/", );
shmid = shmget(key, SEGSIZE, IPC_CREAT|); if shmid == -)
{
printf(" create shared memory error\n");
return -;
} shm = (char *)shmat(shmid, , );
if (- == (int)shm)
{
printf(" attach shared memory error\n");
return -;
} semid = sem_creat(key); for (i = ; i <= ; i++)
{
sleep();
p(semid);
sleep(READTIME);
msg[] = '' + i;
memcpy(shm,msg,sizeof(msg));
sleep();
v(semid);
} shmdt(shm); shmctl(shmid,IPC_RMID,&buf); del_sem(semid); return ; }
client端源码:
/* 编译命令:gcc -o client client.c -g*/
#include<sys/sem.h>
#include<time.h>
#include<sys/ipc.h> #define SEGSIZE 1024
#define READTIME 1 9union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
}arg; /* 打印程序的执行时间函数 */void out_time(void)
{
static long start = ;
time_t tm; if (start == )
{
tm = time(NULL);
start = (long)tm;
printf("now start \n");
} printf("second: %d\n", (long)(time(NULL)) - start);
} /* 创建信号量 */int new_sem(key_t key)
{
union semun sem;
int semid;
sem.val = ;
semid = semget(key, , ); if (- == semid)
{
printf("create semaphore error\n");
exit(-);
} return semid;
} /* 信号量等待函数,等待信号量的值变为0 */void wait_v(int semid)
{
struct sembuf sops = {,
, }; semop(semid, &sops, );
}
int main(int argc, char **argv)
{
key_t key;
int shmid, semid;
char *shm;
char msg[];
char i; key = ftok("/", );
shmid = shmget(key, SEGSIZE, ); if (shmid == -)
{
printf("create shared memory error\n");
return -;
} semid = new_sem(key); for (i = ;i < ;i ++)
{
sleep();
wait_v(semid);
printf("Message geted is: %s \n",shm + );
out_time();
} shmdt(shm); return ; }
下面我们来解释一下程序中的细节问题。
一、信号量:
一个信号量实际上是一个整数,其值大于或等于0代表可供并发进程使用的资源实体;其值小于0时代表正在等待使用的临界区的进程数。用于互斥的信号量初始值应该大于0,且其值只能通过P、V原语操作而改变。
信号量元素组成:
1、表示信号量元素的值;
2、最后操作信号量元素的进程ID
3、等待信号量元素值+1的进程数;
4、等待信号量元素值为0的进程数;
二、主要函数
1.1 创建信号量
int semget( key_t key, /* 标识信号量的关键字,有三种方法:
1、使用IPC——PRIVATE让系统产生,
2、挑选一个随机数,
3、使用ftok从文件路径名中产生
*/
int nSemes, /* 信号量集中元素个数 */
int flag /*IPC_CREAT;IPC_EXCL 只有在信号量集不存在时创建*/
)
成功:返回信号量句柄
失败:返回-1
1.2 使用ftok函数根据文件路径名产生一个关键字
key_t ftok(const char *pathname,int proj_id);
路径名称必须有相应权限
1.3 控制信号量
int semctl( int semid, /* 信号量集的句柄 */
int semnum, /* 信号量集的元素数 */
int cmd, /* 命令 */
/*union senum arg */... //
)
成功:返回相应的值
失败:返回-1
命令详细说明:
IPC_RMID 删除一个信号量
IPC_EXCL 只有在信号量集不存在时创建
IPC_SET 设置信号量的许可权
SETVAL 设置指定信号量的元素的值为 agc.val
GETVAL 获得一个指定信号量的值
GETPID 获得最后操纵此元素的最后进程ID
GETNCNT 获得等待元素变为1的进程数
GETZCNT 获得等待元素变为0的进程数
union senum 定义如下:
union senum{
int val;
struct semid_ds *buf;
unsigned short * array;
}agc;
其中 semid_ds 定义如下:
struct semid_ds{
struct ipc_pem sem_pem; //operation pemission struct
time_t sem_otime; //last semop()time
time_t sem_ctime; //last time changed by semctl()
struct sem *sembase; //ptr to first semaphore in array
struct sem_queue *sem_pending; //pending operations
struct sem_queue *sem_pending_last; //last pending operations
struct sem_undo *undo; //undo requests on this arrary
unsigned short int sem_nsems; //number of semaphores in set
};
1.4 对信号量 +1 或 -1 或测试是否为0
int semop(
int semid,
struct sembuf *sops, //指向元素操作数组
unsigned short nsops //数组中元素操作的个数
)
结构 sembuf 定义
sembuf{
short int sem_num; //semaphore number
short int sem_op; //semaphore operaion
short int sem_flg //operation flag
};
Linux下用信号量实现对共享内存的访问保护的更多相关文章
- Linux进程间通信(六):共享内存 shmget()、shmat()、shmdt()、shmctl()
下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式 ...
- 【转载】Linux进程间通信(六):共享内存 shmget()、shmat()、shmdt()、shmctl()
来源:https://www.cnblogs.com/52php/p/5861372.html 下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相 ...
- linux 下的信号量参数
linux 下的信号量参数 转载自:http://blog.itpub.net/26110315/viewspace-718306/ 信号量是一种锁机制用于协调进程之间互斥的访问临界资源.以确保某种共 ...
- c/c++ linux 进程间通信系列4,使用共享内存
linux 进程间通信系列4,使用共享内存 1,创建共享内存,用到的函数shmget, shmat, shmdt 函数名 功能描述 shmget 创建共享内存,返回pic key shmat 第一次创 ...
- linux进程间的通信之 共享内存
一.共享内存介绍 共享内存是三个IPC(Inter-Process Communication)机制中的一个. 它允许两个不相关的进程访问同一个逻辑内存. 共享内存是在两个正在进行的进程之间传递数据的 ...
- Linux进程IPC浅析[进程间通信SystemV共享内存]
Linux进程IPC浅析[进程间通信SystemV共享内存] 共享内存概念,概述 共享内存的相关函数 共享内存概念,概述: 共享内存区域是被多个进程共享的一部分物理内存 多个进程都可把该共享内存映射到 ...
- Linux下查看内核、CPU、内存及各组件版本的命令和方法
Linux下查看内核.CPU.内存及各组件版本的命令和方法 Linux查看内核版本: uname -a more /etc/*release ...
- 【转】Linux环境进程间通信(五) 共享内存(上)
转自:https://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index1.html 采用共享内存通信的一个显而易见的好处是效率高,因为进程可以 ...
- <转>Linux环境进程间通信(五): 共享内存(上)
http://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index1.html 采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写 ...
随机推荐
- android:#FFFFFFFF 颜色码解析
原文地址:android:#FFFFFFFF 颜色作者:android小鸟 颜色色码为#FFFFFFFF 其中颜色顺序依次为#AARRGGBB 前两位AA代表透明度,FF时表示不透明,00表示透明: ...
- Servlet API遍程常用接口和类
本文主要总结Servlet API遍程常用接口和类 Servlet API http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html ...
- 全球最低功耗蓝牙单芯片DA14580的软件体系 -层次架构和BLE消息事件处理过程
在作者之前发表的<全球最低功耗蓝牙单芯片DA14580的系统架构和应用开发框架分析>.<全球最低功耗蓝牙单芯片DA14580的硬件架构和低功耗>.<全球最低功耗蓝牙单芯片 ...
- android 显示意图
//显示意图 public void enter(View view) { Intent intent = new Intent();//创建一个空的意图 intent.setClassName(ge ...
- XMind快捷键
XMind 是一款非常实用的思维导图软件,可以画各种结构图鱼骨图.二维图.树形图.逻辑图.组织结构图等!下面是常用的快捷键统计! 快捷鍵(Windows) 快捷鍵(Mac) 描述 Ctrl+N Com ...
- Spring学习笔记之 Spring IOC容器(二) 之注入参数值,自动组件扫描方式,控制Bean实例化方式,使用注解方式
本节主要内容: 1. 给MessageBean注入参数值 2. 测试Spring自动组件扫描方式 3. 如何控制ExampleBean实例化方式 4. 使用注解方式重构Jdb ...
- Eclipse和MyEclipse 手动设置 Java代码 注释模板
一.目的 1. 为什么需要注释规范? 注释规范对于程序员而言尤为重要,有以下几个原因: 一个软件的生命周期中,80%的花费在于维护. 几乎没有任何一个软件,在其整个生命周期中,均由最初的开发人员来维 ...
- 在IT的路上,我在成长
在IT的路上,我在成长.很荣幸地加入了博客园这个大家庭. 岁月的航船在不断航行,在成长的脚印我要深深留下,回首已往经历,发现自己成长的路上,将来也会有很多美好的回忆,以及丰硕的果实.
- 烂泥: KVM虚拟机Linux系统增加硬盘
本文由秀依林枫提供友情赞助,首发于烂泥行天下. Linux虚拟机在使用过程中,硬盘空间不够使用.由于前期没有做LVM,所以只能手动添加新的硬盘. 给虚拟机添加硬盘有两种方法: 1.通过virsh at ...
- javascript 特效实现(3)—— 鼠标滑过显示二级菜单效果
1. 关键代码:使用 switch 或 if 判断语句,改变对应的二级菜单显示方式为 block 或 none function selectTabMenu(i){ switch(i){ case 7 ...