Linux 多进程程序调试实例(七)-- 共享内存

共享内存

介绍

  • 共享内存就是两个不相关的进程访问同一个逻辑内存,从而达到两个进程互相通信的效果。共享内存是两个正在运行的进程之间共享和传递数据最有快的一种通信方式;

实现原理

  • 共享内存是两个进程地址通过页面映射到同一个物理地址;

特点

  • 速度快:读写速度是最快的的进程通信方式;
  • 共享内存的生命周期跟随内核。即所有访问共享内存区域的对象都已经正常结束,共享内存区域仍然在内核中存在,除非是显式的删除共享内存区域对象。
  • 缺点是共享内存没有提供同步禁止,需要信号量对共享内存同步访问控制;

函数

1. shmget()

  • 函数说明:创建共享内存
  • 函数原型
int shmget (key_t __key, size_t __size, int __shmflg)
  • 函数介绍:
    • __key:表示IPC的一个唯一标识,由该标识符通过 shmget 生成一个指向共享内存的 ID 值。不同的进程可以通过相同的 key 返回的 ID 值去访问同一块共享内存;
    • __size:指定共享内存的大小,一般为一页大小的整数倍
    • __shmflg: 是一组标志,创建一个新的共享内存,将 shmflg 设置了 IPC_CREAT标志后,共享内存存在就打开。而 IPC_CREAT | IPC_EXCL 则可以创建一个新的,唯一的共享内存,如果共享内存已存在,则返回一个错误。一般该参数值还可以包含一个文件的读写权限;

2.shmctl()

  • 函数说明:操作共享内存
  • 函数原型
int shmctl (int __shmid, int __cmd, struct shmid_ds *__buf);
struct shmid_ds 
{ 
    uid_t shm_perm.uid; 
    uid_t shm_perm.gid; 
    mode_t shm_perm.mode; 
};
  • 函数介绍
    • shm_id:shmge函数返回的内存共享标识符;
    • cmd:要采取的操作,有三种操作
      • IPC_STAT: 把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖 shmid_ds 值
      • IPC_SET:如果进程有足够的权限,就把共享内存当前的关联值设置为 shmid_ds 结构中给出的值
      • IPC_RMID:删除共享内存段
    • buf:指向共享内存模式和访问权限结构。其中 shmid_ds 至少包括上述中的成员变量;

3. shmat()

  • 函数说明:创建共享存储段后,将进程连接到它的地址空间
  • 函数原型:
void *shmat (int __shmid, const void *__shmaddr, int __shmflg)
  • 函数介绍:
    • shm_id:该参数是由 shmget 函数返回的共享内存标识
    • shm_addr:指定共享内存链接到当前进程中的地址位置,通常为空,由系统选择共享内存的地址;
    • shm_flg:是一组标志位,通常为0

4.shmdt() 函数

  • 函数介绍:显示的删除共享内存
  • 函数原型
int shmdt (const void *__shmaddr)
  • 函数介绍:
    • addr: 调用 shmat 函数的返回值

代码

// shmread.cpp
#include<cstdio>
#include<cstdlib>
#include<unistd.h>
#include<sys/shm.h>
#include<cstring>

#define TEXT_SZ 2048
struct shared_use_st{
    int written;
    char text[TEXT_SZ];
};

int main()
{

    // create shared memory
    int shmid = shmget((key_t)1234, sizeof(shared_use_st), 0666|IPC_CREAT);
    if(-1 == shmid){
        fprintf(stderr, "shmget failed\n");
        exit(EXIT_FAILURE);
    }

    // attach shared memory to current process
    void* shm = shmat(shmid, 0, 0);
    if(shm == (void*)-1){
        fprintf(stderr, "shmat failed\n");
        exit(EXIT_FAILURE);
    }
    // printf("Memory attached at %X\n",(int)shm);

    shared_use_st *st_shared = (shared_use_st*)shm;
    st_shared->written = 0;
    // read data from shared memory
    while (1)
    {
        if(st_shared->written != 0) {
            printf("read text:%s\n",st_shared->text);
            sleep(1);
            st_shared->written = 0;
            if(0 == strncmp(st_shared->text,"end",3)){
                break;
            }
        }
        else{
            sleep(1);
        }
    }

    // detach shared memory from current process
    if(-1 == shmdt(shm)){
        fprintf(stderr,"shmdt failed\n");
        exit(EXIT_FAILURE);
    }

    // delete shared memory
    if(-1 == shmctl(shmid, IPC_RMID, 0)){
        fprintf(stderr,"shmctl failed\n");
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
}
// shmwrite.cpp
#include<cstdio>
#include<cstdlib>
#include<unistd.h>
#include<sys/shm.h>
#include<cstring>

#define TEXT_SZ 2048
struct shared_use_st{
    int written;
    char text[TEXT_SZ];
};

int main()
{

    // create shared memory
    int shmid = shmget((key_t)1234, sizeof(shared_use_st), 0666|IPC_CREAT);
    if(-1 == shmid){
        fprintf(stderr, "shmget failed\n");
        exit(EXIT_FAILURE);
    }

    // attach shared memory to current process
    void* shm = shmat(shmid, (void*)0, 0);
    if(shm == (void*)-1){
        fprintf(stderr, "shmat failed\n");
        exit(EXIT_FAILURE);
    }
    // printf("Memory attached at %X\n",(int)shm);

    // write data to shared memory
    shared_use_st *st_shared = (shared_use_st*)shm;
    char buffer[BUFSIZ+1] = {0};
    while (1)
    {
        if(st_shared->written == 1){
            sleep(1);
            printf("Wait...\n");
        }

        printf("Enter data: ");
        fgets(buffer, BUFSIZ, stdin);
        strncpy(st_shared->text, buffer, TEXT_SZ);
        st_shared->written = 1;
        if(0 == strncmp(buffer,"end",3)){
            break;
        }
    }

    if(shmdt(shm) == -1){
        fprintf(stderr, "shmdt failed\n");
        exit(EXIT_FAILURE);
    }

    sleep(2);
    exit(EXIT_SUCCESS);
}

调试过程

普通的两个进程调试

posted @ 2023-02-06 16:34  王清河  阅读(281)  评论(0编辑  收藏  举报