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 Json详解
Json:一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性.业内主流技术为其提供了完整的解决方案(有点类似于正则表达式 ,获得了当今大部分语言的支持),从而可以在不同平台间进行数据交换.J ...
- 设计模式:模版模式(Template Pattern)-转
模版模式 又叫模板方法模式,在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情冴下,重新定义算法中的某些步骤. 我们使用冲泡咖啡和冲泡茶的例子 加工流程 ...
- struts2.3.24 + spring4.1.6 + hibernate4.3.11+ mysql5.5.25开发环境搭建及相关说明
一.目标 1.搭建传统的ssh开发环境,并成功运行(插入.查询) 2.了解c3p0连接池相关配置 3.了解验证hibernate的二级缓存,并验证 4.了解spring事物配置,并验证 5.了解spr ...
- 每日Scrum--No.9
Yesterday:测试软件 Today:写阶段性的总结 Problem: (1)晚上我们的团队进行了收尾工作:第一阶段的任务基本完成,软件主要实现了校园景点照片以及对应的介绍,查询最短路径,查询涉及 ...
- 每日Scrum--No.7
Yesterday:学习和设计路线的编程 Today:编写代码 Problem:.在设计查询参观路线的时候,整个逻辑特别的混乱,设想了各种树,图以及网的遍历问题,但经过多次与同学的交流以及网上的查询资 ...
- Effective Java 37 Use marker interfaces to define types
Marker interface is an interface that contains no method declarations, but merely designates (or &qu ...
- Effective Java 41 Use overloading judiciously
The choice of which overloading to invoke is made at compile time. // Broken! - What does this progr ...
- Effective Java 62 Document all exceptions thrown by each method
Principle Always declare checked exceptions individually, and document precisely the conditions unde ...
- 【mysql】关于Index Condition Pushdown特性
ICP简介 Index Condition Pushdown (ICP) is an optimization for the case where MySQL retrieves rows from ...
- jdbc至sql server的两种常见方法
Statement和prepareStatement sql server中已建立BookPhone数据库,包含bookPhone表,eclipse中有BookPhone类,三个string类型的值 ...