Unix高级编程学习笔记(3)共享内存

Linux进程通信的方式有以下几种

  • 管道(pipe)和有名管道(fifo)
  • 消息队列
  • 共享内存
  • 信号量
  • 信号(signal)
  • 套接字(socket)

在这里我们看一下第3种: 共享内存(shared memory )。
共享内存就是两个或多个进程共享一块内存区域。这种通信方式允许两个不相关的进程能够访问处理同一块内存区域。从而达到进程间数据的交换和处理等。在这些进行通信方式中,共享内存是一种非常高效的通信方式,一种最快的通信方式。为什么快呢?只要我们向一个进程汇总写入的数据,则共享这个内存区域的所有进程都可见,从而达到提醒的目的。可以归为一句话:一处改变,随处可见。
原理:
共享内存是被多个进程共享的一块物理内存,而这些内存就是把共享内存区域映射到自己的虚拟内存中。从而对共享内存进行操作。
共享内存比pipe的优势:
1.用在任何进程,不比考虑进程关系,
2.读走后还存在数据
3.可以随机读取所需要的数据

接下来我们看一下关于共享内存的操作函数:
主要有:shmget();shmat();shmdt();shmctl();
在使用这些函数需引进头文件

#include<sys/ipc.h>
#include<sys/shm.h>

要实现共享内存通信,必须先有共享内存的区域。
我们看一下shmget这个函数

int shmget(key_t _key, size_t _size, int _shmflg);
_key: IPC_PRIVATE或者任何大于0的整数
_size:共享内存大小,必须是页大小的整数倍
_shmflg:标志位,IPC_CREAT 创建,若存在直接返回 IPC_CREAT | IPC_EXCL 若存在该key的共享内存则报错,

ipcs -m: 是查看系统共享内存块信息的命令,我们可以用来查看是否被创建成功。
ipcrm shm shmid:其中shmid是共享内存的标识ID

在shmget函数中,_key值通常是通过ftok函数得到,来生成唯一的KEY值ID。

#include <sys/types.h>
#include <sys/ipc.h>

key_t ftok( char * fname, int id )
fname :文件名(已经存在的文件名),一般使用当前目录”.”
id:子序号,只有8个比特被使用(0-255)

在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。

查询文件索引节点号的方法是: ls -i

#include<sys/shm.h>
#include<sys/ipc.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);

功能:允许进程访问共享内存。
返回值:成功返回共享内存的起始地址,失败返回-1.
参数:
_shmid :共享内存的ID ,也就是shmget()函数的返回值。
_shmaddr:共享内存的起始地址。一般指定为0.
_shmflg:是本进程对共享内存的操作模式。一般指定为0,即可读可写。如果指定为SHM_RDONLY 的话就是只读模式。

使用完了内存我们要进行释放操作。

#include<sys/shm.h>
#include<sys/ipc.h>
int shmdt(_const void *_shmaddr);
功能:释放共享内存,虽然释放不用了,但是共享内存仍然存在。
参数:共享内存的起始地址;就是shmat();函数的返回值。
返回值:成功返回0,失败返回-1.

例子:创建一个共享内存,一个进程往里写,另一个进程每隔一秒读取显示。sudo允许,不然会permission denied

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

int main(int argc ,char *argv[])
{
    int shmid;
    char *addr;
    key_t key;

    key = ftok(".",155);
    printf("key =%d\n",key );  //key
    shmid= shmget(key  ,getpagesize(), IPC_CREAT);

    printf("shmid=%d\n",shmid);  //共享内存标识ID

    if(shmid==-1)
    {
        perror("shmget error:");
        exit(EXIT_FAILURE);
    }
    addr=shmat(shmid,NULL,0); // 允许进程访问共享内存

    if(addr == -1)
    {
        perror("shmat error:");
        exit(EXIT_FAILURE);
    }

    printf(" enter some words\n");
    while(1)
    {

        scanf("%s",addr);
        if(*addr == '#')
            break;      
    }
    return 0;
}
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
int main(int argc ,char *argv[])
{
    int shmid;
    char *addr;
    key_t key;

    key = ftok(".",155);
    printf("key =%d\n",key );  //key
    shmid= shmget(key  ,getpagesize(), IPC_CREAT);

    printf("shmid=%d\n",shmid);  //共享内存标识ID

    if(shmid==-1)
    {
        perror("shmget error:");
        exit(EXIT_FAILURE);
    }
    addr=shmat(shmid,NULL,0); // 允许进程访问共享内存

    if(addr == -1)
    {
        perror("shmat error:");
        exit(EXIT_FAILURE);
    }
    while(1)
    {
        sleep(1);
        printf("%s\n", addr);

        if(*addr == '#')
            break;      
    }


    return 0;
}

你可能感兴趣的:(unix,socket,内存)