当前位置: 首页 > article >正文

使用Posix共享内存区实现进程间通信

使用Posix共享内存区实现进程间通信

使用Posix共享内存区通常涉以下步骤:

  • 进程A 调用shm_open 创建共享内存区
  • 进程A调用ftruncate修改共享内存区大小
  • 进程A 调用mmap将共享内存区映射到进程地址空间ptrA
  • 进程A 使用ptrA对共享内存区进程更改
  • 进程B 使用shm_open打开已有共享内存区
  • 进程B 调用fstat获取共享内存区大小
  • 进程B 调用mmap将共享内存区映射到进程地址空间ptrB
  • 进程B 使用ptrB对共享内存区进行更改
  • 最后由进程A/B调用shm_unlink删除共享内存区
1、shm_open 创建/打开共享内存区

shm_open调用成功后返回共享内存区的文件描述符, 并在/dev/shm目录下生成相应的文件。

shm_open函数声明包含在文件 sys/mman.h 中;

#include <sys/mman.h>
#include <sys/stat.h>        /* For mode constants */
#include <fcntl.h>           /* For O_* constants */

int shm_open(const char *name, int oflag, mode_t mode);

oflag的值包含在文件 fcntl.h


#define O_RDONLY     00   //只读
#define O_WRONLY     01   //只写
#define O_RDWR       02   //可读可写
#define O_CREAT      0100 //创建
#define O_EXCL       0200 //如果共享内存区已存在则返错误

mode的值包含在文件sys/stat.h


#define	S_IRUSR	__S_IREAD	/* Read by owner.  */
#define	S_IWUSR	__S_IWRITE	/* Write by owner.  */
#define	S_IXUSR	__S_IEXEC	/* Execute by owner.  */

#define	S_IRGRP	(S_IRUSR >> 3)	/* Read by group.  */
#define	S_IWGRP	(S_IWUSR >> 3)	/* Write by group.  */
#define	S_IXGRP	(S_IXUSR >> 3)	/* Execute by group.  */

#define	S_IROTH	(S_IRGRP >> 3)	/* Read by others.  */
#define	S_IWOTH	(S_IWGRP >> 3)	/* Write by others.  */
#define	S_IXOTH	(S_IXGRP >> 3)	/* Execute by others.  */
2、ftruncate修改内存区大小

ftruncate包含在头文件unistd.h

/* Truncate the file FD is open on to LENGTH bytes.  */
 int ftruncate (int __fd, __off_t __length)
fd:shm_ope返回的描述符
length:共享内存区的大小
3、fstat获取文件大小

fstat包含在头文件sys/stat.h

在打开已存在的共享内存区时,可以用fstat获取共享内存区的大小。


/* Get file attributes for the file, device, pipe, or socket
   that file descriptor FD is open on and put them in BUF.  */
int fstat (int __fd, struct stat *__buf)
fd:shm_open返回的描述符
stat.st_size是共享内存区的大小
4、mmap将共享内存区映射到进程地址空间

mmap包含在头文件mman.h


void *mmap (void *__addr, size_t __len, int __prot,
		   int __flags, int __fd, __off_t __offset)
参数
__addr: 映射到进程的地址,直接传入NULL就行。
__len: 共享内存区的大小。

__prot: 权限
PROT_READ   可读
PROT_WRITE  可写
PROT_EXEC   可执行

__flags:映射方式
MAP_SHARED: 当前进程所做的修改其他进程可见 
MAP_PRIVATE:当前进程所做的修改其他进程不可见

__fd: shm_open返回的描述符 
__offset:偏移量,一般都传入0
5、shm_unlink删除共享内存区

shm_unlink和shm_open在同一文件中,用于删除共享内存区。

/* Remove shared memory segment.  */
int shm_unlink (const char *__name);
6、练习
  • 进程shmserver创建共享内存区shmtest,并创建子进程等待其他进程向shmtest中写入数据。
  • 进程shmcli向共享内存区shmtest写入数据,并给进程shmserver发送信号。
  • 进程shmserver取出共享内存区shmtest中的数据并输出到窗口。

cond_h.h

#define COUNT 10

typedef struct shm_block
{
    pthread_mutex_t mutex;
    pthread_cond_t  cond;
    int arr[COUNT];
    int nput;
    int nread;
    int ncount;
}shm_block;

void shm_block_init(shm_block* shm)
{
    pthread_mutexattr_t attr;            
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);  
    pthread_mutex_init(&shm->mutex, &attr);
    pthread_mutexattr_destroy(&attr);

    pthread_condattr_t cond_attr;
    pthread_condattr_init(&cond_attr);
    pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
    pthread_cond_init(&shm->cond, &cond_attr);
    pthread_condattr_destroy(&cond_attr);
    
    bzero(shm->arr, sizeof(shm->arr));
    shm->ncount  = 0;
    shm->nput    = 0;
    shm->nread   = 0;
}

shm_server.c

#include<unistd.h>
#include<pthread.h>
#include<mqueue.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<strings.h>
#include<wait.h>
#include"cond_h.h"

int main(int argc, char* argv[])
{   
    if (argc != 2)
    {
        printf("shmcreate [shmname]\n");
        return 0;
    }
    
    shm_block shm;
    shm_block_init(&shm);

    int shmfd = shm_open(argv[1], O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
    if (shmfd == -1)
    {
        printf("%d : %s\n",__LINE__, strerror(errno));
        return -1;
    }

    printf("create shared memory %s. \n", argv[1]);

    if (ftruncate(shmfd, sizeof(shm_block)) < 0)
    {
        printf("%d : %s\n",__LINE__, strerror(errno));
        return -1;
    }
    
    shm_block* pBlock =  (shm_block*)mmap(NULL, sizeof(shm_block), PROT_WRITE|PROT_READ, MAP_SHARED, shmfd, 0);
    if (NULL == pBlock)
    {
        printf("%d : %s\n",__LINE__, strerror(errno));
        return -1;
    }
    close(shmfd);
    
    memcpy(pBlock, &shm, sizeof(shm));
    int pid = fork();
    if (pid == 0)
    {
        int fd = shm_open(argv[1], O_RDWR, S_IRUSR|S_IWUSR);
        if (fd < 0)
        {
            printf("%d : %s\n",__LINE__, strerror(errno));
            return -1;
        }
        struct stat st;
        fstat(fd, &st);
        printf("%d: st_size = %d\n", __LINE__, st.st_size);
        shm_block *p = (shm_block*)mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        if (NULL == p)
        {
            printf("%d : %s\n",__LINE__, strerror(errno));
            return -1;
        }

        while (1)
        {

            pthread_mutex_lock(&p->mutex);

            while (p->ncount <= 0)
                pthread_cond_wait(&p->cond, &p->mutex);

            int value = p->arr[p->nread];
            p->ncount--;
            p->nread++;
            p->nread %= COUNT; 

            pthread_mutex_unlock(&p->mutex);

            printf("%d: p->nread:%d, arr[nread] : %d\n",__LINE__, p->nread, value);
        }
        
        munmap(p, st.st_size);
        close(fd);
        return 0;
    }

    int stat_loc = 0;
    waitpid(pid, &stat_loc, 0);
    munmap(pBlock, sizeof(shm));
    if (WIFEXITED(stat_loc)) 
        printf("Child process exited with status: %d\n", WEXITSTATUS(stat_loc));
    
    return 0;
}

shm_cli.c

#include<sys/mman.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include"cond_h.h"

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        printf("cond_put <shmname> <value>");
        return -1;
    }
    char *shmname = argv[1];
    int   value   = atoi(argv[2]);
    int   shmfd   = shm_open(shmname, O_RDWR, 0);
    
    if (-1 == shmfd)
    {
        printf("%d: %s\n", __LINE__, strerror(errno));
        return -1;
    }

    shm_block* p =  (shm_block*)mmap(NULL, sizeof(shm_block), PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0);
    if (NULL == p)
    {
        printf("%d: %s\n", __LINE__, strerror(errno));
        return -1;
    }

    close(shmfd);

    pthread_mutex_lock(&p->mutex);
    do
    {
        if (p->ncount == COUNT)
            break;
        p->arr[p->nput] = value;
        printf("count: %d,  nput: %d, nread: %d,arr[nput]:%d\n", p->ncount, p->nput, p->nread,value);

        p->nput         = (p->nput + 1) % COUNT;
        p->ncount++;
        
        if (p->ncount == 1)
            pthread_cond_signal(&p->cond);
        
    } while (0);

    pthread_mutex_unlock(&p->mutex);
    close(shmfd);
    return 0;
}

使用方法:


unlink /dev/shm/shmtest
gcc shm_server.c -lrt -lpthread -o shmserver
./shmserver shmtest

gcc shm_cli.c -lrt -lpthread -o shmcli
./shmcli  shmtest 33
./shmcli  shmtest 34
./shmcli  shmtest 35

shmserver输出:


create shared memory shmtest. 
60: st_size = 144
83: p->nread:1, arr[nread] : 33
83: p->nread:2, arr[nread] : 34
83: p->nread:3, arr[nread] : 35

http://www.kler.cn/a/532708.html

相关文章:

  • 4 前置技术(下):git使用
  • WPS怎么使用latex公式?
  • 蓝桥与力扣刷题(234 回文链表)
  • gitea - fatal: Authentication failed
  • ChatGPT怎么回事?
  • Intel 与 Yocto 项目的深度融合:全面解析与平台对比
  • 二维数组 C++ 蓝桥杯
  • vue生命周期及其作用
  • 基于机器学习的布伦特原油价格的分析与研究
  • 通向AGI之路:人工通用智能的技术演进与人类未来
  • 数据库索引:秋招面试中的经典高频题目 [特殊字符](索引原理/操作/优缺点/B+树)
  • module_init宏是什么?
  • web-XSS-CTFHub
  • python学opencv|读取图像(五十六)使用cv2.GaussianBlur()函数实现图像像素高斯滤波处理
  • 线程创建与管理 - 创建线程、线程同步(C++)
  • git进阶--6---git stash
  • 一文了解边缘计算
  • 数据降维技术研究:Karhunen-Loève展开与快速傅里叶变换的理论基础及应用
  • RabbitMQ深度探索:简单实现 MQ
  • nlp文章相似度
  • STM32 串口发送与接收
  • 硬件产品经理:需求引力模型(DGM)
  • 用 OpenCV 画圆:让图像处理更简单有趣
  • 昇思打卡营第五期(MindNLP特辑)番外:硅基流动 x 华为云DeepSeek V3 API推理MindTinyRAG
  • 排序算法--冒泡排序
  • 最新版Node.js下载安装指定版本图文版教程(非常详细)