转自: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下用信号量实现对共享内存的访问保护的更多相关文章

  1. Linux进程间通信(六):共享内存 shmget()、shmat()、shmdt()、shmctl()

    下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式 ...

  2. 【转载】Linux进程间通信(六):共享内存 shmget()、shmat()、shmdt()、shmctl()

    来源:https://www.cnblogs.com/52php/p/5861372.html 下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相 ...

  3. linux 下的信号量参数

    linux 下的信号量参数 转载自:http://blog.itpub.net/26110315/viewspace-718306/ 信号量是一种锁机制用于协调进程之间互斥的访问临界资源.以确保某种共 ...

  4. c/c++ linux 进程间通信系列4,使用共享内存

    linux 进程间通信系列4,使用共享内存 1,创建共享内存,用到的函数shmget, shmat, shmdt 函数名 功能描述 shmget 创建共享内存,返回pic key shmat 第一次创 ...

  5. linux进程间的通信之 共享内存

    一.共享内存介绍 共享内存是三个IPC(Inter-Process Communication)机制中的一个. 它允许两个不相关的进程访问同一个逻辑内存. 共享内存是在两个正在进行的进程之间传递数据的 ...

  6. Linux进程IPC浅析[进程间通信SystemV共享内存]

    Linux进程IPC浅析[进程间通信SystemV共享内存] 共享内存概念,概述 共享内存的相关函数 共享内存概念,概述: 共享内存区域是被多个进程共享的一部分物理内存 多个进程都可把该共享内存映射到 ...

  7. Linux下查看内核、CPU、内存及各组件版本的命令和方法

    Linux下查看内核.CPU.内存及各组件版本的命令和方法 Linux查看内核版本: uname -a                        more /etc/*release       ...

  8. 【转】Linux环境进程间通信(五) 共享内存(上)

    转自:https://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index1.html 采用共享内存通信的一个显而易见的好处是效率高,因为进程可以 ...

  9. <转>Linux环境进程间通信(五): 共享内存(上)

    http://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index1.html 采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写 ...

随机推荐

  1. iOS开发之UIImage等比缩放

    iOS开发之UIImage等比缩放 评论功能真不错 评论开通后,果然有很多人吐槽.谢谢大家的支持和关爱,如果有做的不到的地方,还请海涵.毕竟我一个人的力量是有限的,我会尽自己最大的努力大家准备一些干货 ...

  2. WebService核心文件【server-config.wsdd】详解及调用示例

    WebService核心文件[server-config.wsdd]详解及调用示例 作者:Vashon 一.准备工作 导入需要的jar包: 二.配置web.xml 在web工程的web.xml中添加如 ...

  3. Erlang 虚拟机 BEAM 指令集之内存管理相关的指令

    翻看 BEAM 虚拟机指令集的时候(在编译器源码目录下:lib/compiler/src/genop.tab),会发现有一些和内存分配/解除分配相关的指令,如下所示: allocate StackNe ...

  4. 你所不知道的SQL Server数据库启动过程(用户数据库加载过程的疑难杂症)

    前言 本篇主要是上一篇文章的补充篇,上一篇我们介绍了SQL Server服务启动过程所遇到的一些问题和解决方法,可点击查看,我们此篇主要介绍的是SQL Server启动过程中关于用户数据库加载的流程, ...

  5. 【mysql】关于checkpoint机制

    一.简介 思考一下这个场景:如果重做日志可以无限地增大,同时缓冲池也足够大,那么是不需要将缓冲池中页的新版本刷新回磁盘.因为当发生宕机时,完全可以通过重做日志来恢复整个数据库系统中的数据到宕机发生的时 ...

  6. TCP/IP包格式详解

    文章参考地址:http://blog.chinaunix.net/uid-20698826-id-4700710.html http://blog.csdn.net/mrwangwang/articl ...

  7. SQL将用户表中已存在的数据所有姓名(汉字)转换为拼音首字母

    实现方法: --函数 Create function [dbo].[fn_GetPy](@str nvarchar(4000)) returns nvarchar(4000) --用于加密 --WIT ...

  8. nyoj 120 校园网络

    题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=120 思路:先将原图强连通缩点为新图,统计新图中入度,出度为0的点的个数,两者取最大值即为 ...

  9. [转]Oracle如何实现创建数据库、备份数据库及数据导出导入的一条龙操作

    本文转自:http://www.cnblogs.com/wuhuacong/archive/2012/03/09/2387680.html Oracle中对数据对象和数据的管理,无疑都是使用PL/SQ ...

  10. Chorme中启动阿里旺旺误点取消启动并记住选择,如何更改。

    今天在Chorme中启动阿里旺旺误点取消启动并记住选择,然后如何也点不开了.从网上找到了一种解决方法: 找到路径   C:\Users\\AppData\Local\Google\Chrome\Use ...