【linux高级程序设计】(第十一章)System V进程间通信 4

共享内存

共享内存主要用于实现进程间大量数据传输。

共享内存的数据结构定义:

系统对共享内存的限制:

共享内存与管道的对比:

可以看到,共享内存的优势:

1.共享内存只需复制2次,而管道需要4次

2.共享内存不需要切换内核态与用户态,而管道需要。

共享内存效率高!

int shmget (key_t __key, size_t __size, int __shmflg) :创建共享内存

第一个参数:key值

第二个参数:欲创建的共享内存段的大小(字节)

第三个参数:shmflg创建标识,包括IPC_CREAT, IPC_EXCL, IPC_NOWAIT, SHM_R(可读), SHM_W(可写)

int shmctl (int __shmid, int __cmd, struct shmid_ds *__buf) :共享内存控制

第一个参数:要操作的共享内存标识符

第二个参数:要执行的操作,IPC_RMID, iPC_SET, IPC_STAT, IPC_INFO, 超级用户还有 SHM_LOCK(锁定共享内存段), SHM_UNLOCK(解锁共享内存段)

第三个参数:临时共享内存变量信息

void *shmat (int __shmid, __const void * __shmaddr, int __shmflg) : 挂载共享内存到当前进程,返回共享内存首地址

第一个参数:要操作的共享内存标识符

第二个参数:指定共享内存映射地址,如果是0,系统选择。

第三个参数:指定共享内存段的访问权限和映射条件,0表示可读可写

int shmdt (__const void *__shmaddr) :把共享内存与当前进程分离,参数为共享内存映射地址

测试,在只读共享内存中写信息:

#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<errno.h>

int main(int argc, char * argv[])
{
    key_t key;
    int shm_id;
    char *ptr;
    key = ftok("/", 10);
    shm_id = shmget(key, 100, IPC_CREAT|SHM_R); //创建shm
    printf("get the shm id is %d\n", shm_id);  //打印id
    if((ptr = (char *)shmat(shm_id, NULL, SHM_RDONLY)) == NULL)  //只读方式挂载
    {
        if(shmctl(shm_id, IPC_RMID, NULL) == -1)  //如果失败则删除
            perror("Failed to remove memory segment");
        exit(EXIT_FAILURE);
    }
    //打印挂载地址
    printf("the attach add is %p\n", ptr);
    printf("now try to write the memory\n");
    *ptr = ‘d‘;
    printf("*ptr =%c\n", *ptr);
    shmdt(ptr);
    shmctl(shm_id, IPC_RMID, 0);
}

发生段错误:

父子进程间对共享内存的约定:

  • fork()的子进程继承父进程挂载的共享内存。
  • 调用exec执行新程序,则共享内存被自动卸载。
  • 如果调用了exit(),挂载的共享内存与当前进程脱离关系。

下面是一个应用的例子

实现两个没有亲缘关系进程的通信,一个负责写,另一个负责接收。用信号量实现同步,即写的时候不可读,读的时候不可写。用一元信号量实现,0表示可写,1表示可读

注意:在代码实现中,实际上是读写轮流操作的,即写一次,读一次。并没有达到真正多进程的效果。

代码经验证,可以使用

发送端代码:

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

int main(int argc, char *argv[])
{
    int running = 1;
    int shid;
    int semid;
    int value;
    void *sharem = NULL;
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_flg = SEM_UNDO;
    //创建信号量
    if((semid = semget((key_t)123456, 1, 0666|IPC_CREAT)) == -1)
    {
        perror("semget");
        exit(EXIT_FAILURE);
    }
    //初始化信号量为0
    if(semctl(semid,0,SETVAL,0) == -1)
    {
        printf("sem init error");
        if(semctl(semid, 0, IPC_RMID, 0) != 0)
        {
            perror("semctl");
            exit(EXIT_FAILURE);
        }
        exit(EXIT_FAILURE);
    }
    //创建共享内存
    shid = shmget((key_t)654321, (size_t)2048, 0600|IPC_CREAT);  //创建共享内存
    if(shid == -1)
    {
        perror("shmget");
        exit(EXIT_FAILURE);
    }
    //挂载共享内存到当前进程
    sharem = shmat(shid, NULL, 0);
    if(sharem == NULL)
    {
        perror("shmat");
        exit(EXIT_FAILURE);
    }
    while(running)
    {
        //测试信号量值,如果为0则可写
        if((value = semctl(semid, 0, GETVAL)) == 0)
        {
            printf("write data operate\n");
            printf("please input something:");
            scanf("%s", sharem);
            sem_b.sem_op = 1;
            //执行信号量加1操作,允许读
            if(semop(semid, &sem_b, 1) == -1)
            {
                fprintf(stderr, "semaphore_p failed\n");
                exit(EXIT_FAILURE);
            }
        }
        //比较是否是结束符号
        if(strcmp(sharem, "end") == 0)
                running--;
    }
    shmdt(sharem);
        return 0;
}

接收端代码:

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

int main(int argc, char *argv[])
{
    int running = 1;
    int shid;
    int semid;
    int value;
    void *sharem = NULL;
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_flg = SEM_UNDO;
    //创建信号量
    if((semid = semget((key_t)123456, 1, 0666|IPC_CREAT)) == -1)
    {
        perror("semget");
        exit(EXIT_FAILURE);
    }
    //创建共享内存
    shid = shmget((key_t)654321, (size_t)2048, 0600|IPC_CREAT);  //创建共享内存
    if(shid == -1)
    {
        perror("shmget");
        exit(EXIT_FAILURE);
    }
    //挂载共享内存到当前进程
    sharem = shmat(shid, NULL, 0);
    if(sharem == NULL)
    {
        perror("shmat");
        exit(EXIT_FAILURE);
    }
    while(running)
    {
        //测试信号量值,如果为1则可读
        if((value = semctl(semid, 0, GETVAL)) == 1)
        {
            printf("read data operate\n");
            sem_b.sem_op = -1;
            //执行信号量减1操作,允许写
            if(semop(semid, &sem_b, 1) == -1)
            {
                fprintf(stderr, "semaphore_p failed\n");
                exit(EXIT_FAILURE);
            }
            printf("%s\n", sharem);
        }
        //比较是否是结束符号
        if(strcmp(sharem, "end") == 0)
                running--;
    }
    shmdt(sharem);
    //删除共享内存
    if(shmctl(shid, IPC_RMID, 0) != 0)
    {
        perror("shmctl");
        exit(EXIT_FAILURE);
    }
    //删除信号量
    if(semctl(semid, 0, IPC_RMID, 0) != 0)
    {
        perror("semctl");
        exit(EXIT_FAILURE);
    }
    return 0;
}
时间: 2024-10-09 22:24:50

【linux高级程序设计】(第十一章)System V进程间通信 4的相关文章

javascript高级程序设计 第十一章--DOM扩展

javascript高级程序设计 第十一章--DOM扩展DOM最主要的扩展就是选择符API.HTML5和Element Traversal Selectors API:定义了两个方法 querySelector() 和 querySelectorAll(),能够基于CSS选择符从DOM中取得元素.querySelector()方法接收一个CSS选择符,返回该模式匹配的第一个元素,querySelectorAll()接收的参数一样,但是返回NodeList实例: matchesSelector()

读书笔记 - js高级程序设计 - 第十一章 DOM扩展

对DOM的两个主要的扩展 Selectors API HTML5 Element Traversal 元素遍历规范 querySelector var body = document.querySelector("body"); var myDiv = document.querySelector("#myDiv"); 取得id为myDiv的元素 var selected = document.querySelector(".selected")

Linux程序设计学习笔记----System V进程间通信(信号量)

关于System V Unix System V,是Unix操作系统众多版本中的一支.它最初由AT&T开发,在1983年第一次发布,因此也被称为AT&T System V.一共发行了4个System V的主要版本:版本1.2.3和4.System V Release 4,或者称为SVR4,是最成功的版本,成为一些UNIX共同特性的源头,例如"SysV 初始化脚本"(/etc/init.d),用来控制系统启动和关闭,System V Interface Definitio

javascript高级程序设计 第十三章--事件

javascript高级程序设计 第十三章--事件js与HTML的交互就是通过事件实现的,事件就是文档或浏览器窗口中发生的一些特定的交互瞬间. 事件流:事件流描述的是从页面中接收事件的顺序,IE的是事件冒泡流,Netscape的是事件捕获流,这个两个是完全相反的事件流概念. 事件冒泡:由最具体的元素接收,然后逐级向上传播到更高级的节点,即事件沿DOM树向上传播,直到document对象. 事件捕获:不大具体的节点应该更早接收到事件,相当于沿DOM节点树向下级传播直到事件的实际目标,在浏览器中,是

Javascript高级程序设计——第三章:基本概念

javascript高级程序设计——第三章:基本概念 一.语法 EMCA-262通过叫做ECMAScript的“伪语言”为我们描述了javascript实现的基本概念 javascript借鉴了C的语法,区分大小写,标示符以字母.下划线.或美元符号($)开头,注释可以用 // 或者/* */ 严格模式: ECMAScript 5引入了严格模式,在严格模式下不确定的行为将得到处理,通过在顶部添加 “use strict”来启用严格模式: function fuc(){ "use strict&qu

【linux高级程序设计】(第十一章)System V进程间通信 1

System V, 曾经也被称为 AT&T System V,是Unix操作系统众多版本中的一支. 传统上,System V 被看作是两种UNIX"风味"之一(另一个是 BSD).然而,随着一些并不基于这两者代码的UNIX实现的出现,例如 Linux 和 QNX, 这一归纳不再准确. System V IPC基础 System V 的IPC机制主要有消息队列.信号量和共享内存3种机制. shell中的 ipcs 命令可以查看当前系统中正在使用的IPC工具. shell中的 ip

《Unix网络编程》卷2 读书笔记 第3章- System V IPC

1. 概述 三种类型的System V IPC:System V 消息队列.System V 信号量.System V 共享内存区 System V IPC在访问它们的函数和内核为它们维护的信息上共享许多类似点.本章讲述所有这些共同属性. 下图汇总了所有System V IPC 函数 2. key_t键.ftok函数 头文件sys/types.h把数据类型key_t定义为一个整数,通常是一个至少32位的整数 #include <sys/ipc.h> key_t ftok (const char

细说linux IPC(五):system V共享内存

system V共享内存和posix共享内存类似,system V共享内存是调用shmget函数和shamat函数.           shmget函数创建共享内存区,或者访问一个存在的内存区,类似系统调用共享内存的open和posix共享内存shm_open函数.shmget函数原型为: #include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int shmflg); key: 函

细说linux IPC(十):system V 消息队列

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] system V消息队列和posix消息队列类似,linux系统这两种消息队列都支持.先来看一下system V消息队列相关操作及其函数. msgget()函数创建一个消息队列或打开一个消息队列. #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h&

《JavaScript高级程序设计第五章--引用类型》之Object对象和array对象

这一章主要就是介绍各种内置对象的用法,认识其经常用到的属性和方法. 5.1Object类型 创建objec的方式,一种是new Object(),一种是对象字面量(简化创建包含大量属性的对象的过程) var person = { name = "Nicholas"; age = 27 };//最后一个属性不必添加逗号,ie7等会导致错误 //在使用对象字面量语法时,属性名也可以使用字符串.这里的数值属性会自动转字符串. var person = { "name" :