码迷,mamicode.com
首页 > 系统相关 > 详细

Linux IPC 共享内存用法

时间:2016-05-12 23:26:34      阅读:283      评论:0      收藏:0      [点我收藏+]

标签:

Linux IPC 常见的方式

写 Linux Server 端程序,必然会涉及到进程间通信 IPC. 通信必然伴随着同步机制,下面是一些常见的通信与同步机制:

  1. 进程间通信:匿名管道,命名管道,消息队列,共享内存,Domain Socket, 本机 TCP Socket,文件
  2. 进程间同步:信号,信号量
  3. 线程间同步:条件变量,互斥量,读写锁,自旋锁,Barrier.

对于大部分的业务场景,本机 TCP Socket 足以,现在Linux 也对本机 TCP Socket做了很好的优化。而且如果以后需要分机器部署进程,那么程序不需要怎么改动,十分方便。至于 Domain Socket,应用也很广泛,可以看这篇文章:UNIX Domain Socket IPC

共享内存IPC的原理

用共享内存做IPC手段的最大优势是效率最高,缺点是需要借助其他同步机制

共享内存IPC的基本原理也很简单:把同一块物理内存映射到多个进程的虚拟地址空间,进程虚拟地址布局可以看这篇:Linux虚拟地址空间布局。Linux 在 <sys/shm.h> 提供了相关操作的接口:

  1. 获取 利用 key 创建或获取一个存在的共享内存对象;
  2. 关联 attach, 关联到当前进程的虚拟地址空间;
  3. 分离 detach, 从当前进程中分离;
  4. 控制 如: 设参数, 锁定, 释放等;

详细的函数接口说明可以看: Linux进程间通信——使用共享内存

共享内存 IPC 例子

下面的 demo 一个读,一个写,IPC采用共享内存,同步就用最简单的条件变量配合。最终实现在一个进程读标准输入,另外一个进程输出到控制台。

可以使用 ipcs -m 查看系统使用的共享内存 IPC资源列表。

公共头文件:

/* file: shm_comm.h */

#ifndef _SHM_COMM_H
#define _SHM_COMM_H

#define MY_SHM_KEY 0x12
#define READ_SHM 1
#define WRITE_SHM -1

typedef struct {
    int flag;
    char buff[1020];
}__attribute__((packed)) S_SHM_BUF;  // 单字节对齐,方便 ipcs -m 查看对比大小

#endif

读进程

/* file:shm_read.c */

#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include "shm_comm.h"

int main()
{
    void *shm = NULL;
    S_SHM_BUF *shbuf;
    int ret = 0;
    int shmid = 0;

    /* 由 key 申请共享内存, 得到 id */
    shmid = shmget(MY_SHM_KEY, sizeof(S_SHM_BUF), IPC_CREAT);
    if (-1 == shmid) {
        printf("get share memory failed!\n");
        exit(EXIT_FAILURE);
    }

    /* 根据 id 把共享内存 attach 到进程地址空间,得到首地址 */
    shm = shmat(shmid, 0, 0);
    if (-1L == (long)shm) {
        printf("share memory attach failed!\n");
    }
    printf("share memory attached at %p\n", shm);

    shbuf = (S_SHM_BUF*)shm;
    while (1) {
        if (READ_SHM == shbuf->flag) {
            printf("read: %s\n", shbuf->buff);
            shbuf->flag = WRITE_SHM;
            if (0 == strncmp(shbuf->buff, "end", 3)) {
                break;
            }
        } else {
            sleep(1);
        }
    }

    /* 根据首地址,把共享内存从进程空间 detach 掉 */
    ret = shmdt(shm);
    if (-1 == ret) {
        printf("share memory detach failed!\n");
        exit(EXIT_FAILURE);
    }

    /* 根据id,让操作系统删掉共享内存 */
    ret = shmctl(shmid, IPC_RMID, 0);
    if (-1 == ret) {
        printf("share memory remove failed!\n");
        exit(EXIT_FAILURE);
    }

    printf("program end ok!\n");
    return 0;
}

写进程

/* file: shm_write.c */

#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include "shm_comm.h"

int main()
{
    void *shm = NULL;
    S_SHM_BUF *shbuf;
    int ret = 0;
    int shmid = 0;

    shmid = shmget(MY_SHM_KEY, sizeof(S_SHM_BUF), IPC_CREAT);
    if (-1 == shmid) {
        printf("get share memory failed!\n");
        exit(EXIT_FAILURE);
    }

    shm = shmat(shmid, 0, 0);
    if (-1L == (long)shm) {
        printf("share memory attach failed!\n");
    }
    printf("share memory attached at %p\n", shm);

    shbuf = (S_SHM_BUF*)shm;
    memset(shbuf, 0, sizeof(*shbuf));
    shbuf->flag = WRITE_SHM;

    while (1) {
        if (WRITE_SHM == shbuf->flag) {
            printf("write: ");
            scanf("%s", shbuf->buff);
            shbuf->flag = READ_SHM;
            if (0 == strncmp(shbuf->buff, "end", 3)) {
                break;
            }
        } else {
            sleep(1);
        }
    }

    ret = shmdt(shm);
    if (-1 == ret) {
        printf("share memory detach failed!\n");
        exit(EXIT_FAILURE);
    }

    printf("program end ok!\n");
    return 0;
}

Makefile

# Makefile
CFLAGS  = -Wall -Werror -g -m64
compile = $(CC) $(CFLAGS) $^ -o $@

.PHONY : all
all : shm_read.bin shm_write.bin

# 注意 makefile 的缩进要用<TAB>
shm_read.bin : shm_read.c shm_comm.h
    $(compile)

shm_write.bin : shm_write.c shm_comm.h
    $(compile)

.PHONY : clean
clean:
    rm *.bin

Linux IPC 共享内存用法

标签:

原文地址:http://blog.csdn.net/thisinnocence/article/details/51348478

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!