进程间通信--共享内存和信号

共享内存

多个进程共同映射同一内核中内存
高效率,没有同步
分配,绑定,脱离,释放
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);

ipcs 查看共享内存段

   Resources may be specified as follows:
   -m     shared memory segments
   -q     message queues
   -s     semaphore arrays
   -a     all (this is the default)
   The output format may be specified as follows:
   -t     time
   -p     pid
   -c     creator
   -l     limits
   -u     summary

获取/创建:shmget
#include
#include
int shmget(key_t key, size_t size, int shmflg);
参数:key 唯一对应的一个共享内存的对象,也可取值IPC_PRIVATE
size 大小
shmflg 获取/创建共享内存的标志位,
常用取值:IPC_CREAT 不存在则创建共享内存
IPC_EXCL 和IPC_CREAT共同使用,共享内存存在则报错
return 成功返回共享内存ID,失败返回-1

key_t ftok(const char *pathname, int proj_id);

/*
    key = ftok("/", 'a');
    if((shmid = shmget(key, 100, 
            IPC_CREAT | S_IRUSR | S_IWUSR)) == -1)
    {
        perror("shmget failed");
        return 1;
    }
*/

绑定
void *shmat(int shmid, const void *shmaddr, int shmflg);
// char *string = shmat(shmid, NULL, 0);
参数
shmid 待绑定的共享内存ID
shmaddr NULL,系统提供合适的绑定地址
shmflg SHM_RDONLY 只读绑定;0 读写绑定
返回值 绑定成功,返回可以访问的 共享内存空间起始地址,失败,返回(void *) -1

解绑定:shmdt
int shmdt(const void *shmaddr);
//shmdt(string);
参数:shmaddr shmat 的返回值
返回值:成功返回 0,失败返回 -1

删除
shmctl:用于对指定的共享内存进行控制
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:shmid 待进行操作的共享内存ID
cmd 需要进行的命令分类 (例:IPC_STAT 获取共享内存的相关信息)
buf 根据第二个参数的取值提供空间用于获取相应的值
返回值 :失败 -1
共享内存函数介绍:

//共享内存
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    // 共享内存ID
    int shmid = 0;
    // 用于获取/创建共享内存的key值
    key_t key;
     // 1.获取/创建

    //key_t ftok( const char * fname, int id )
        //fname就是你指定的文件名(已经存在的文件名),一般使用当前目录
        //id 为子序号。虽然是int类型,但是只使用8bits(1-255)
    key = ftok("/", 'a');

    // int shmget(key_t key, size_t size, int shmflg);
    // 参数:
    //  key 唯一对应一个共享内存对象,也可取值IPC_PRIVATE
    //  size 获取/创建的共享内存大小
    //  shmflg 获取/创建共享内存的标志位,
    //          IPC_CREAT    不存在则创建共享内存
    //          IPC_EXCL     和IPC_CREATE共同使用,共享内存存在则报错退出
    //          S_IRUSR 用户读 S_IWUSR 写 S_IRGRP 用户组读 S_IROTH  其他组读     
    // 返回值:成功,返回共享内存ID;失败,返回-1
    if((shmid = shmget(key, 100, 
            IPC_CREAT | S_IRUSR | S_IWUSR)) == -1)
    {
        perror("shmget failed");
        return 1;
    }
    
    // 2.绑定
    //void *shmat(int shmid, const void *shmaddr, int shmflg);
    // 参数:
    // shmid    待绑定的共享内存id
    // shmaddr  NULL,系统提供合适的绑定地址
    // shmflg   SHMRDONLY   只读绑定;0  读写绑定
    // 返回值:绑定成功,返回可以访问共享内存空间起始地址
    //      失败,返回(void *) -1
    char *string = shmat(shmid, NULL, SHM_RDONLY);
    
    // 对共享内存进行读写操作
    printf("string : %s\n", string);
    
    // 3.解绑定
    // int shmdt(const void *shmaddr);
    // 参数:
    // shmaddr  shmat的返回值
    // 返回值:成功,返回0;失败,-1
    shmdt(string);
    
    // 4.删除

    return 0;
}

信号量通信

信号量函数参数及函数详解并举例
进程间通信----信号量----程序例子

信号量数组的创建进程的函数介绍

// 本进程为
#include 
#include 
#include 
#include 

union semun {
    int val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short *array;  /* Array for GETALL, SETALL */
    struct seminfo *__buf;  /* Buffer for IPC_INFO
                                           (Linux-specific) */
};

int main(int argc, char *argv[])
{
    int semid;
    key_t key;

    key = ftok("/", 'a');

    // 1.创建
    // int semget(key_t key, int  nsems,  int semflg);
    // 参数:
    // key  用于创建信号量数组的key值
    // nsems 创建的信号两数组中信号量的个数
    // semflg 与shmget类似,为信号量数组的标志位
    //      IPC_CREAT新建   IPC_EXCL 若已存在则报错    SIRUSR 读 SIWUER 写
    // 返回值:成功,返回信号量数组的ID;失败,-1
    if((semid = semget(key, 1, IPC_CREAT | 0666)) == -1)
    {
        perror("semget failed");
        return 1;
    }
    printf("semid : %d\n", semid);

    // 2.初始化
    // int semctl(int semid, int semnum, int cmd, /*union semun arg*/);
    // 参数:
    // semid    待操作的信号量数组的ID
    // semnum   待操作的信号量数组中的信号两的编号(从0开始)
    // cmd      执行的具体操作种类
        /*
        .IPC_STAT读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
        ·IPC_SET设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
        ·IPC_RMID将信号量集从内存中删除。
        ·GETALL用于读取信号量集中的所有信号量的值。
        ·GETNCNT返回正在等待资源的进程数目。
        ·GETPID返回最后一个执行semop操作的进程的PID。
        ·GETVAL返回信号量集中的一个单个的信号量的值。
        ·GETZCNT返回正在等待完全空闲的资源的进程数目。
        ·SETALL设置信号量集中的所有的信号量的值。
        ·SETVAL设置信号量集中的一个单独的信号量的值。
        */
    // union semun  根据cmd取值的不同,来传递不同的参数,
    //  arg为联合体的副本,而不是指针,联合体要自己定义

    union semun arg;
    arg.val = 1;        // 指定下标信号量的初始值,0是忽略
    semctl(semid, 0, SETVAL, arg);

    // 3.wait操作(-1)
    // int semop(int semid, struct sembuf *sops, size_t nsops);
    // 参数:
    // semid    待操作的信号量集ID
    // sops nsops   组合起来传递一个struct sembuf类型的数组,以供信号量集中的各个编号的信号量进行操作
    struct sembuf s_op1;
    s_op1.sem_num = 0;
    s_op1.sem_op = -1;
    s_op1.sem_flg = SEM_UNDO;
    semop(semid, &s_op1, 1);
    /*
        sem_num:操作信号在信号集中的编号,第一个信号的编号是0。
        sem_op:如果其值为正数,该值会加到现有的信号内含值中。
        通常用于释放所控资源的使用权;
        如果sem_op的值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。
        通常用于获取资源的使用权;
        如果sem_op的值为0,如果没有设置IPC_NOWAIT,则调用该操作的进程或者线程将暂时睡眠,直到信号量的值为0;
        否则,进程或者线程不会睡眠,函数返回错误EAGAIN。
        sem_flg:信号操作标志,可能的选择有两种
        IPC_NOWAIT //对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息。
        SEM_UNDO //程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。
        nsops:信号操作结构的数量,恒大于或等于1。
    */
    system("ipcs -s");
    printf("destroy sem array...\n");

    // 4.post操作(+1)
    struct sembuf s_op2;
    s_op2.sem_num = 0;
    s_op2.sem_op = 1;
    s_op2.sem_flg = SEM_UNDO;
    semop(semid, &s_op2, 1);

    printf("before destroy sem array...\n");
    system("ipcs -s");

    // 5.销毁
    semctl(semid, 0, IPC_RMID);

    printf("after destroy sem array...\n");
    system("ipcs -s");

    return 0;
}

你可能感兴趣的:(进程间通信--共享内存和信号)