linux c 共享内存实现

1.共享内存被映射进程空间后,存在于进程空间的什么位置?
存在于进程数据段

2.共享内存最大限制是多少?
最大限制0x2000000byte

 

(1)创建共享内存

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);

返回值:共享内存标志符
key为输出参数
size应该为1024整数倍,4k对其
shmflg权限标志:需要|IPC对象存取权限(如0600)
IPC_CREAT:如果内核中不存在键值与key相等的共享内存,则新建共享内存;如果存在这样的共享内存,返回此共享内存的标志服
IPC_CREATE | IPC_EXCL:如果内存中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错。


(2)将共享内存映射到自己的内存空间shmat

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

shmaddr:当前进程中的地址位置。(void*)0,系统自动选择地址。
返回值:映射地址的第一个字节


(3)解除映射:shmdt
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr)

#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr)

(4)控制共享内存shmctl

#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

cmd:
IPC_STAT:得到共享内存状态
IPC_SET:改变共享内存状态
IPC_RMID:删除共享内存
。。。

           struct shmid_ds {
               struct ipc_perm shm_perm;
               size_t          shm_segsz;
               time_t          shm_atime;
               time_t          shm_dtime;
               time_t          shm_ctime;
               pid_t           shm_cpid;
               pid_t           shm_lpid;
               shmatt_t        shm_nattch;
               ...
           };
          struct ipc_perm {
               key_t          __key; 
               uid_t          uid;
               gid_t          gid; 
               uid_t          cuid;
               gid_t          cgid; 
               unsigned short mode; 
               unsigned short __seq;
           };
(5)ftok
 

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);

返回key_t键值,-1为失败
pathname:存在并且可以访问
proj_id:0-255

 

共享内存实现:

defined.h

#ifndef __DEFINED_H_
#define __DEFINED_H_

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>

#define SHM_KEY_PATH "/home/flz/keypath"  // 共享内存key路径,必须存在
#define SHMEM_SIZE (1024 * 4)             // 共享内存大小,1024整数倍

typedef struct mhdr
{
    unsigned char from;         // 1:client, 2:service
    unsigned char op;           // 操作类型
    unsigned short length;      // 数据长度
}mhdr;

void create_file(char* filename);
int create_shmem();           // 创建共享内存
void destroy_shmem(void *addr);         // 销毁共享内存
#endif

comom.c

#include "defined.h"

// 创建共享内存
int create_shmem()
{
    create_file(SHM_KEY_PATH);

    key_t key = ftok(SHM_KEY_PATH, 0);
    if(key < 0)
    {
        printf("ftok() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        return -1;
    }

    int shmid = shmget(key, SHMEM_SIZE, IPC_CREAT | 0666);
    if(shmid < 0)
    {
        printf("shmget() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        return -1;
    }

    return shmid;
}

// 销毁共享内存
void destroy_shmem(void *addr)
{
    int ret = shmdt(addr);
    if(ret < 0)
    {
        printf("shmdt() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
    }
}

// 创建文件
void create_file(char* filename)
{
    char* lppos0 = filename;
    char* lppos1 = strrchr(filename, '/');
    char szDir[256] = { 0 };
    memcpy(szDir, filename, lppos1 - lppos0);

    printf("mkdir %s\n", szDir);
    if(mkdir(szDir, 0771) < 0)
    {
        printf("mkdir() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
    }

    printf("creating file:%s\n", filename);
    FILE *fp = fopen(filename, "w+");
    if(fp == NULL)
    {
        printf("fopen() failed, errno=%d,errmsg=%s\n", errno, strerror(errno));
    }
    fclose(fp);
}


client.c

#include "defined.h"

// 读线程
void* readthread(void* param)
{
    const void* shmaddr = param;        // 共享内存地址
    
    while(1)
    {
        sleep(1);
        mhdr header = { 0 };
        memcpy(&header, shmaddr, sizeof(mhdr));

        printf("share memory data: from=%d, op=%d, length=%d\n", header.from, header.op, header.length);
        if(header.length > 0)
        {
            char data[SHMEM_SIZE] = { 0 };
            memcpy(data, shmaddr + sizeof(mhdr), header.length);
            printf("data:\n%s\n", data);
        }
    }

    printf("thread quit.\n");
    return NULL;
}

int main()
{
    int shmid = create_shmem();         // 创建共享内存
    if(shmid < 0)
    {
        printf("create share memory failed!\n");
        return -1;
    }
    printf("created shmem, id=%d\n", shmid);


    // 映射共享内存
    void *shmaddr = shmat(shmid, NULL, 0);
    if(shmaddr == NULL)
    {
        printf("create share memory failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        goto end;
    }

    // 从共享内存数据    
    pthread_t tid = 0;
    if(pthread_create(&tid, NULL, readthread, shmaddr) < 0)
    {
        printf("pthread_create() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        goto end;
    }

    if(pthread_join(tid, NULL) < 0)
    {
        printf("pthread_join() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        goto end;
    }
    
end:
    
    destroy_shmem(shmaddr);         // 销毁共享内存

    return 0;
}



service.c

#include "defined.h"

#include <stdlib.h>
#include <time.h>

// 写线程
void* write_thread(void *param)
{
    printf("running write thread...\n");
    srand(time(0));
        
    void* shmaddr = param;

    while(1)
    {
        mhdr header = { 0 };
        header.from = 1;
        header.op = 0;
        header.length = 5 + rand()%256;
        char buff[300] = { 0 };

        for(int i=0;i<header.length;i++)
        {
            int num = rand()%30;
            char ch = 0;
            if(num>=0 && num <= 9)
            {
                ch = '0' + num;
            }
            else if(num >= 10 && num<=26)
            {
                ch = (num - 10) + 'a';
            }
            else if(num >= 27 && num <= 53)
            {
                ch = (num - 27) + 'A';
            }
            buff[i] = ch;
        }
        buff[header.length] = 0;
        memcpy(shmaddr, &header, sizeof(header));
        memcpy(shmaddr + sizeof(header), buff, header.length);

        sleep(1);
    }

    return NULL;
}


int main()
{
    // 创建共享内存
    int shmid = create_shmem();
    if(shmid < 0)
    {
        printf("create share memory faild\n");
        return 0;
    }
    printf("share memory id:%d\n", shmid);
    
    void* shmaddr = shmat(shmid, NULL, 0);
    if(shmaddr == NULL)
    {
        printf("shmat() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        goto end;
    }

    printf("share memory addr:0x%x\n", shmaddr);
    
    pthread_t tid = 0;
    // 不断地往共享内存写数据
    if(pthread_create(&tid, NULL, write_thread, shmaddr) < 0)
    {
        printf("pthread_create() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        goto end;
    }

    if(pthread_join(tid, NULL) < 0)
    {
        printf("pthread_join() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        goto end;
    }

end:
    // 销毁共享内存
    destroy_shmem(shmaddr);
    return 0;
}


运行结果:

flz@rt1000-virtual-machine:~/test/shm$ ./service &
[1] 18947
flz@rt1000-virtual-machine:~/test/shm$ mkdir /home/flz
mkdir() failed, errno=17, errmsg=File exists
creating file:/home/flz/keypath
share memory id:6
share memory addr:0x45eac000
running write thread...

flz@rt1000-virtual-machine:~/test/shm$ ./client
mkdir /home/flz
mkdir() failed, errno=17, errmsg=File exists
creating file:/home/flz/keypath
created shmem, id=6
share memory data: from=1, op=0, length=124
data:
bBncg3e382jB5BaB81gAnj3AA3d7dpignck2f45gBg6pegnnaak3ln1ii6hn169gilipifbg1hc8qA167d1lBo180j2np3a5pk0dBclClpC9n07md9dbpfkqqebl
share memory data: from=1, op=0, length=156
data:
lqq4q120nneinn3n1qC21aA8mf46Ap8ad4e26g2Cag9p25i3nhAokg3c2Cblhj10ng2loAcq5el7j22cblB18n62n9nako2525Ajo9fCnCC41ng4ffBf8qhn5a3pq60C3jijCpaeo9jhpAea4chd84B5e20a
share memory data: from=1, op=0, length=7
data:
m13cbe3
share memory data: from=1, op=0, length=114
data:
ohnqB3lqhn0Ca5Ce44kBqmBignmA7pq15kA3fal23mn5jebni1l6ojo249Cbqq518oAf5ih022Bmg9fqbC2AaiCfAkiogfhgae17paCA4Ajc7A8ii2

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值