转自: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. Android 正则表达式

    1.相关知识链接 正则表达式语法   https://msdn.microsoft.com/zh-cn/library/ae5bf541(v=vs.80).aspx 正则表达式入门教程   http: ...

  2. Linux useful command

    查看linux系统里面的各个目录.文件夹的大小和使用情况, 先切换到需要查看的目录,如果需要查看所有linux目录的使用情况就直接切换到系统跟目录,然后执行: du -h --max-depth=1 ...

  3. iOS之UI--辉光动画

    前言:学习来自YouXianMing老师的博客:<辉光UIView的category>以及YouXianMing老师的github源码:< GlowView >    而我个人 ...

  4. sublime text 3 如何安装 package control

    sublime text3 是个很好的编辑工具,前端程序员觉得她很好,我是在一次视频中看到她能帮助自动完成很多快捷的操作. 为什么安装? 如果想要给sublime text 中安装别的插件(这里称呼为 ...

  5. C++ 构造函数中调用虚函数

    我们知道:C++中的多态使得可以根据对象的真实类型(动态类型)调用不同的虚函数.这种调用都是对象已经构建完成的情况.那如果在构造函数中调用虚函数,会怎么样呢? 有这么一段代码: class A { p ...

  6. 远程连接mysql容易遇到的2个问题

    1."com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure The las ...

  7. Windows下查看端口占用

    最近在重新安装Mysql的时候,发现3306默认端口被占用了.类似的情况常常遇到,想查看到底是哪个程序把这个端口占用了. 下面是我google找到的方法,和大家分享. 1. 首先,使用netstat ...

  8. Effective Java 45 Minimize the scope of local variables

    Principle The most powerful technique for minimizing the scope of a local variable is to declare it ...

  9. Effective Java 75 Consider using a custom serialized form

    Principle Do not accept the default serialized form without first considering whether it is appropri ...

  10. HTTP 协议的头部

    转自:http://network.51cto.com/art/201509/490594.htm HTTP首部字段有四种类型:通用首部字段,请求首部字段,响应首部字段,实体首部字段. 通用首部字段: ...