linux进程间通信-----System V共享内存总结实例

共享内存简介

共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。

进程1映射到该共享内存区域后,就可以通过映射之后得到的首地址p1,直接对那一片共享内存区域进行操作;
进程2映射到同一块内存区域后,也可以得到映射之后的那一片共享内存的首地址p2,通过p2可以直接对那一片共享内存区域进行操作;

System V共享内存API

1:创建共享内存

#include 
#include 
int shmget(key_t key, size_t size, int shmflg);
key:这个共享内存段名字,可以自己指定,也可以通过ftok函数来生成一个随机的key
size:共享内存大小
shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1
ret = shmget(0x2234, sizeof(Teacher), 0666 | IPC_CREAT);//存在就使用旧的 不存在就创建

#include 
#include 
key_t ftok(const char *pathname, int proj_id);//随机产生key值


2:将共享内存段连接到进程地址空间

#include 
#include 
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid: 共享内存标识,就是函数shmget的返回值
shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1

shmaddr:指定连接的地址
shmaddr为NULL,核心自动选择一个地址
shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - (shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表示连接操作用来只读共享内存

3:将共享内存段与当前进程脱离
#include 
#include 
int shmdt(const void *shmaddr);
shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段

4:用于控制共享内存

#include 
#include 
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作(有三个可取值)
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1

IPC_STAT:获得共享内存数据结构的信息
IPC_SET :设置共享内存数据结构的信息
IPC_RMID:删除共享内存段
 struct shmid_ds {
     struct ipc_perm shm_perm;    /* Ownership and permissions */
     size_t          shm_segsz;   /* Size of segment (bytes) */
     time_t          shm_atime;   /* Last attach time */
     time_t          shm_dtime;   /* Last detach time */
     time_t          shm_ctime;   /* Last change time */
     pid_t           shm_cpid;    /* PID of creator */
     pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
     shmatt_t        shm_nattch;  /* No. of current attaches */
     ...
 };

The ipc_perm structure is defined as follows (the highlighted fields are settable using IPC_SET):

 struct ipc_perm {
     key_t          __key;    /* Key supplied to shmget(2) */
     uid_t          uid;      /* Effective UID of owner */
     gid_t          gid;      /* Effective GID of owner */
     uid_t          cuid;     /* Effective UID of creator */
     gid_t          cgid;     /* Effective GID of creator */
     unsigned short mode;     /* Permissions + SHM_DEST and
                                 SHM_LOCKED flags */
     unsigned short __seq;    /* Sequence number */
 };

实例1:

进程1创建键值是0x1111的共享内存,大小为1024字节;进程1从标准输入读入数据并写入到共享内存中;当进程1输入over的时候,删除该共享内存,并退出;
进程2打开键值是0x1111的共享内存,并从里面读取数据然后输出到标准输出上面;当进程2收到over之后退出;
备注:当两个进程都运行的时候,输入命令ipcs可以看到键值是0x1111的共享内存的连接数是2,也就是说有两个进程已经连接到了该共享内存区域;

write_shm.cpp

/*************************************************************************
	> File Name: write_shm.cpp
	> Author: 
	> Mail: 
	> Created Time: 2015年12月21日 星期一 11时15分23秒
 ************************************************************************/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

/*
1: 创建一块共享内存
2:连接到共享内存,并向共享内存中写入数据
3:脱离该共享内存区域
*/
#define SHMSIZE 1024

int main(int argc, char *argv[])
{
    /*
    if(argc < 2){
        cout << "input the pathname fo generate key..."<< endl;
        exit(-1);
    }*/
    key_t key = 0x1111;//ftok(argv[1], 'a');
    
    int shmid = shmget(key, SHMSIZE, 0666|IPC_CREAT);
    if(shmid == -1){
        cerr << "shmget error ...." << endl;
        exit(-1);
    }

    char * p = (char *)shmat(shmid, NULL, 0);
    pid_t pid = getpid();
    cout << "process " << pid << " write: ";
    while(cin.getline(p, SHMSIZE)){
        if(strcmp(p, "over") == 0){
            break;
        }
        cout << "process " << pid << " write: ";
    }
//脱离该共享内存区域,并删除该共享内存区域
    shmdt(p);
    shmctl(shmid, IPC_RMID, NULL);
    cout << "已经删除了共享内存,并退出。\n";
    exit(0);
}

read_shm.cpp

/*************************************************************************
	> File Name: read_shm.cpp
	> Author: 
	> Mail: 
	> Created Time: 2015年12月21日 星期一 11时15分23秒
 ************************************************************************/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

/*
连接到共享内存,并向共享内存中读入数据
脱离该共享内存区域
*/
#define SHMSIZE 1024

int main(int argc, char *argv[])
{
    key_t key = 0x1111; 
   //当共享内存中有数据的时候它才会立刻返回,否则该函数会阻塞在这里 
    int shmid = shmget(key, SHMSIZE, 0666);
    if(shmid == -1){
        cerr << "shmget error ...." << endl;
        exit(-1);
    }

    pid_t pid = getpid();
    char * p = (char *)shmat(shmid, NULL, 0);
    cout << "process " << pid << " read: ";
    while(1){
        if(strlen(p) != 0)
            cout << p << endl;
        else
            continue;
        if(strcmp(p, "over") == 0){
            break;
        }
        cout << "process " << pid << " read: ";
        memset(p, 0, SHMSIZE);
    }
    cout << "进程退出。\n";
    exit(0);
}
linux进程间通信-----System V共享内存总结实例_第1张图片


linux进程间通信-----System V共享内存总结实例_第2张图片

你可能感兴趣的:(Linux技术,服务器编程)