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

共享内存

多个进程共同映射同一内核中内存
高效率,没有同步
分配,绑定,脱离,释放
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 <sys/ipc.h>
#include <sys/shm.h>
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 <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>

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 <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

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;
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容