对于共享内存的知识点介绍,大家可以参阅下面这两篇文章:

共享内存基础知识01

共享内存基础知识02

注意:

如果在代码中没有手动删除,共享内存并不会随着程序的终止而自动清理!

大家可以使用shell命令:ipcs -m 查看自己的共享内存区。效果如下图所示:

共享内存创建demo 共享内存 dest_信号量

其中:
第一列就是共享内存的key;
第二列是共享内存的编号shmid;
第三列就是创建的用户owner;
第四列就是权限perms;
第五列为创建的大小bytes;
第六列为连接到共享内存的进程数nattach;
第七列是共享内存的状态status。其中显示“dest”表示共享内存段已经被删除,但是还有用户在使用它,当该段内存的mode字段设置为SHM_DEST时就会显示“dest”。当用户调用shmctl的IPC_RMID时,内存先查看多少个进程与这个内存关联着,如果关联数为0,就会销毁这段共享内存,否者设置这段内存的mod的mode位为SHM_DEST,如果所有进程都不用则删除这段共享内存。

图中所有者为root的共享内存区是我刚才创建的,我们来查看一下这段共享内存的具体信息:输入shell命令:ipcs -m -i 2654237   

共享内存创建demo 共享内存 dest_共享内存创建demo_02

如果程序中没有删除它,此时,我们可以使用shell命令:ipcrm shmid  来删除指定共享内存区。(示例:ipcrm 2654237)

大家可以通过 man ipcs 查看其更多用法。

下面是自己写的一个示例。详细介绍了使用共享内存的主要步骤,以及对共享内存进行操作之前,使用信号量机制进行同步保护。当然,大家也可以使用记录锁来进行同步。

server.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <sys/sem.h>

#define IPCKEY 0x19890319  //为增强可移植性,自定义key_t 
#ifdef _SEM_SEMUN_UNDEFINED    //关于信号量的知识,可以查看我的前一篇文章
union semun
{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *__buf;
};
#endif

void my_err(char *);
int semphore_p(int);
int semphore_v(int);

int main(void)
{
    printf("----------Start----------\n");
    int shm_id;
    void *addr;
    int page_size=getpagesize(); //Get memory page size
    if((shm_id=shmget(IPCKEY,page_size,0640|IPC_CREAT|IPC_EXCL))==-1) //注意:共享内存区段大小必须为当前系统架构页面大小的整数倍。否则,系统自动扩充至整数倍,但是最后一页的剩余空间将无法访问。
        my_err("shmget error");
    addr=shmat(shm_id,0,0);  // Attach shared memory
    if(addr==(void *)-1)
        my_err("shmat error");

//在对共享内存操作前,使用信号量进行保护同步,避免多个进程同时操作。
    int sem_id;
    union semun semun_val;
    if((sem_id=semget(IPCKEY,1,IPC_CREAT))==-1)
        my_err("semget error");
    semun_val.val=1;
    if(semctl(sem_id,0,SETVAL,semun_val)==-1)
        my_err("semctl set error");
    if(semphore_p(sem_id)==-1) // 信号量P操作
        my_err("semphore_p error");

    strncpy(addr,"test share memory.",18); //对共享内存区进行操作。You can do something else.

    printf("write into shm ok\n");
    sleep(10);
    if(semphore_v(sem_id)==-1) //信号量V操作
        my_err("semphore_v error");
    

    if(shmdt(addr)==-1) //Detach shared memory
        my_err("shmdt error");
    if(shmctl(shm_id,IPC_RMID,NULL)==-1) //Remove shared memory
        my_err("shmctl error");
    printf("shm removed,process end\n");
    exit(0);
}

void my_err(char *str)
{
    perror(str);
    exit(1);
}

int semphore_p(int semid)
{
    struct sembuf _sembuf;
    _sembuf.sem_num=0;
    _sembuf.sem_op=-1;
    _sembuf.sem_flg=SEM_UNDO;
    if(semop(semid,&_sembuf,1)==-1)
        return -1;
    return 0;
}

int semphore_v(int semid)
{
    struct sembuf _sembuf;
    _sembuf.sem_num=0;
    _sembuf.sem_op=1;
    _sembuf.sem_flg=SEM_UNDO;
    if(semop(semid,&_sembuf,1)==-1)
        return -1;
    return 0;
}



client.c 

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>

#define IPCKEY 0x19890319
#ifdef _SEM_SEMUN_UNDEFINED
union semun
{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *__buf;
};
#endif

void my_err(char *);
int semphore_p(int);
int semphore_v(int);

int main(void)
{
    printf("----------client start------------\n");
    int shm_id;
    void *addr;
    int page_size=getpagesize();
    if((shm_id=shmget(IPCKEY,page_size,0640))==-1)
        my_err("shmget error");
    addr=shmat(shm_id,0,0);
    if(addr==(void *)-1)
        my_err("shmat error");

    int sem_id;
    if((sem_id=semget(IPCKEY,1,0))==-1)
        my_err("semget error");
    if(semphore_p(sem_id)==-1)
        my_err("semphore_p error");    

    printf("server msg:%s\n",addr);

    if(semphore_v(sem_id)==-1)
        my_err("semphore_v error");

    if(shmdt(addr)==-1)
        my_err("shmdt error");
    printf("end\n");
    exit(0);
}

void my_err(char *str)
{
    perror(str);
    exit(1);
}

int semphore_p(int semid)
{
    struct sembuf _sembuf;
    _sembuf.sem_num=0;
    _sembuf.sem_op=-1;
    _sembuf.sem_flg=SEM_UNDO;
    if(semop(semid,&_sembuf,1)==-1)
        return -1;
    return 0;
}

int semphore_v(int semid)
{
    struct sembuf _sembuf;
    _sembuf.sem_num=0;
    _sembuf.sem_op=1;
    _sembuf.sem_flg=SEM_UNDO;
    if(semop(semid,&_sembuf,1)==-1)
        return -1;
    return 0;
}