1. 信号量函数的介绍


如果用semget创建了一个新的信号量集对象时,则semid_ds结构成员变量的值设置如下:

    sem_otime设置为0。sem_ctime设置为当前时间。msg_qbytes设成系统的限制值。sem_nsems设置为nsems参数的数值。semflg的读写权限写入sem_perm.mode中。sem_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。


sops为指向sembuf数组,定义所要进行的操作序列。下面是信号量操作举例。

struct sembuf sem_get={0,-1,IPC_NOWAIT}; /将信号量对象中序号为0的信号量减1/

struct sembuf sem_get={0,1,IPC_NOWAIT}; /将信号量对象中序号为0的信号量加1/

struct sembuf sem_get={0,0,0}; /进程被阻塞,直到对应的信号量值为0/

flag一般为0,若flag包含IPC_NOWAIT,则该操作为非阻塞操作。若flag包含SEM_UNDO,则当进程退出的时候会还原该进程的信号量操作,这个标志在某些情况下是很有用的,比如某进程做了P操作得到资源,但还没来得及做V操作时就异常退出了,此时,其他进程就只能都阻塞在P操作上,于是造成了死锁。若采取SEM_UNDO标志,就可以避免因为进程异常退出而造成的死锁。



参考网址:https://blog.csdn.net/guoping16/article/details/6584043

2. 示例代码

新建semaphore.h文件

#ifndef __SEM_H__
#define __SEM_H__#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/types.h>#define PATHNAME "./"
#define PROJ_ID 0x666union semun
{int val; //单个信号的值 struct semid_ds *buf;unsigned short *array;struct seminfo *__buf;
};int create_sem_set(int nsem);int get_sem_set(int nsem);int init_sem_set(int sem_set_id, int which_sem);int sem_p(int sem_set_id, int which_sem);int sem_v(int sem_set_id, int which_sem);int destroy_sem_set(int sem_set_id);#endif

新建semaphore.c文件

#include "semaphore.h"static int sem_set(int nsem, int semflag)
{key_t key = ftok(PATHNAME, PROJ_ID);if (key < 0){perror("ftok failure");exit(-1);}int sem_set_id = semget(key, nsem, semflag);if (sem_set_id < 0){perror("semget failure");exit(-1);}return sem_set_id;
}int create_sem_set(int nsem)
{if (nsem <= 0){perror("nsem <= 0");exit(-1);}return sem_set(nsem, IPC_CREAT | IPC_EXCL | 0666);
}int get_sem_set(int nsem)
{if (nsem <= 0){perror("nsem <= 0");exit(-1);}return sem_set(nsem, IPC_CREAT);
}int init_sem_set(int sem_set_id, int which_sem)
{union semun my_semun;my_semun.val = 1;//semun中val的值去设置信号集(sem_set)中单个sem的值int ret = semctl(sem_set_id, which_sem, SETVAL, my_semun);if (ret == -1){perror("semctl error");exit(-1);}return 0;
}static int sem_operatons(int sem_set_id, int which_sem, int op)
{struct sembuf sb;//sembuf is as follows://unsigned short sem_num//short sem_op//short sem_flgsb.sem_num = which_sem;sb.sem_op = op;sb.sem_flg = SEM_UNDO;return semop(sem_set_id, &sb, 1);
}int sem_p(int sem_set_id, int which_sem)
{ return sem_operatons(sem_set_id, which_sem, -1);
}int sem_v(int sem_set_id, int which_sem)
{ return sem_operatons(sem_set_id, which_sem, +1);
}int destroy_sem_set(int sem_set_id)
{int ret = semctl(sem_set_id, 0, IPC_RMID, NULL); if (ret == -1){perror("semctl failure");exit(-1);}return ret;
}

新建shm.h文件

#ifndef __SHM__
#define __SHM__#include<stdlib.h>
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>#define PATHNAME "./"
#define PROJ_ID 0x666int create_shm(int sz);int get_shm(int sz);void* malloc_addr(int shm_id);int free_addr(const void* addr);int destroy_shm(int shm_id);#endif 

新建shm.c文件

#include"shm.h"static int shm(int sz, int flag)
{key_t key = ftok(PATHNAME, PROJ_ID);if (key == -1){perror("ftok failure");exit(-1);}int shm_id = shmget(key, sz, flag);if (shm_id < 0){perror("shmget failure");exit(-1);}return shm_id;
}int create_shm(int sz)
{return shm(sz, IPC_CREAT | IPC_EXCL | 0666);
}int get_shm(int sz)
{return shm(sz, IPC_CREAT);
}void* malloc_addr(int shm_id)
{return shmat(shm_id, NULL, 0);
}int free_addr(const void* addr)
{return shmdt(addr);
}int destroy_shm(int shm_id)
{return shmctl(shm_id, IPC_RMID, NULL);
}

新建test.c文件

#include"shm.h"
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
#include"semaphore.h"
typedef struct cPicInfo{int size;char state;
}cPicInfo;typedef struct cPicBuf{char *picbuf;int *picbuf_size;char *picbuf_state; //0 :not use 1: will using 2: is using
}cPicBuf;#define SHM_SIZE       (4096 + sizeof(cPicInfo))
#define PICBUF_NUM      (10)cPicBuf* getfreebuf_frome_mem(char *sharebuf, int perpic_size)
{int i;cPicBuf picbuf[PICBUF_NUM];char *psharebuf = sharebuf + 1;for( i = 0; i <PICBUF_NUM; i++){picbuf[i].picbuf = psharebuf + i * SHM_SIZE;picbuf[i].picbuf_size = (int *)(picbuf[i].picbuf + ( SHM_SIZE - sizeof(cPicInfo)));picbuf[i].picbuf_state = (char *)(picbuf[i].picbuf_size) + sizeof(int);if(*picbuf[i].picbuf_state == 0){*picbuf[i].picbuf_state = 2;break;}}printf("get free i:%d\n",i);return i < PICBUF_NUM ?  &picbuf[i] : NULL;
}cPicBuf* getcolbuf_frome_mem(char *sharebuf, int perpic_size)
{int i;cPicBuf picbuf[PICBUF_NUM];char *psharebuf = sharebuf + 1;for( i = 0; i <PICBUF_NUM; i++){picbuf[i].picbuf = psharebuf + i * SHM_SIZE;picbuf[i].picbuf_size = (int *)(picbuf[i].picbuf + ( SHM_SIZE - sizeof(cPicInfo)));picbuf[i].picbuf_state = (char *)(picbuf[i].picbuf_size) + sizeof(int);if(*picbuf[i].picbuf_state == 2){*picbuf[i].picbuf_state = 3;break;}}printf("get col i:%d\n",i);return i < PICBUF_NUM ?  &picbuf[i] : NULL;
}int main()
{int ret;//创建信号量并初始化int sem_set_id = create_sem_set(2);init_sem_set(sem_set_id, 0);init_sem_set(sem_set_id, 1);//创建共享内存int shm_id = create_shm(SHM_SIZE * PICBUF_NUM + 1);//创建子进程pid_t pid = fork();if (pid < 0){perror("fork failure");exit(-1);}else if (pid == 0) //子进程{char* buf = (char*)malloc_addr(shm_id);int count = 0;cPicBuf* freebuf;buf[0] = 1;while(1){//if(buf[0] == 1){    int ret = semctl(sem_set_id, which_sem, SETVAL, my_semun);if( 1 == (ret =semctl(sem_set_id, 1, GETVAL, NULL))){printf("zi ret: %d\n", ret);
;               count++;sem_p(sem_set_id, 0);    freebuf = getfreebuf_frome_mem(buf, SHM_SIZE);if(freebuf != NULL)*freebuf->picbuf_size = count;buf[0] = 2;sem_v(sem_set_id, 0); sem_p(sem_set_id, 1);}if(count == 10)break;}free_addr(buf);}else //父进程{char* buf = (char*)malloc_addr(shm_id);//usleep(500000);//让子进程先P操作cPicBuf* colbuf;int count1 = 0;while(1){//if(buf[0] == 2){if( 0 == (ret = semctl(sem_set_id, 1, GETVAL, NULL))){printf("fu ret: %d\n", ret);count1++;sem_p(sem_set_id, 0); colbuf = getcolbuf_frome_mem(buf, SHM_SIZE);if(colbuf != NULL){printf("picbuf_size :%d \n",*colbuf->picbuf_size);}buf[0] = 1;sem_v(sem_set_id, 0);  sem_v(sem_set_id, 1);                }if(count1 == 10)break;}free_addr(buf);destroy_shm(shm_id);destroy_sem_set(sem_set_id);}return 0;
}

新建Makefile文件

test:test.c semaphore.c shm.cgcc -o $@ $^
.PHONY:clean
clean:rm -f test

【基础知识】进程通信之共享内存+信号量相关推荐

  1. linux 进程原理内存,linux进程通信之共享内存原理(基于linux 1.2.13)

    1 有一个全局的结构体数据,每次需要一块共享的内存时(shmget),从里面取一个结构体,记录相关的信息. struct shmid_ds { // 权限相关 struct ipc_perm shm_ ...

  2. Windows进程通信之共享内存通信(C++)

    首先是概念:https://baike.baidu.com/item/%E5%85%B1%E4%BA%AB%E5%86%85%E5%AD%98/2182364?fr=aladdin 这是比较官方的解释 ...

  3. window下进程通信之共享内存初探

    一.内存存储的好处 1.两个进程之间进行数据交换,一般可以通过文件或者数据库.使用文件或者数据库作为存取介质的,一般是对运行效率可能没有太高的要求.对于结构稍微复杂的数据使用文件存储似乎不是一个太好的 ...

  4. linux进程间的通信(C): 共享内存

    一.共享内存介绍 共享内存是三个IPC(Inter-Process Communication)机制中的一个. 它允许两个不相关的进程访问同一个逻辑内存. 共享内存是在两个正在进行的进程之间传递数据的 ...

  5. 共享内存 传一个类指针_大神是如何学习 Go 语言之为什么使用通信来共享内存...

    为什么这么设计(Why's THE Design)是一系列关于计算机领域中程序设计决策的文章,我们在这个系列的每一篇文章中都会提出一个具体的问题并从不同的角度讨论这种设计的优缺点.对具体实现造成的影响 ...

  6. WIN32 进程间通讯-共享内存

    一.引言     在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯.WIN32 API提供了许多函数使我们能够方便高效的进行进程间的通讯,通过这些函数我们可以控制不同进程间的数据交换 ...

  7. 如何理解“不要通过共享内存来通信,而应该通过通信来共享内存”?

    不要通过共享内存来通信,而应该通过通信来共享内存 这是一句风靡golang社区的经典语,对于刚接触并发编程的人,该如何理解这句话? 如何理解"不要通过共享内存来通信,而应该通过通信来共享内存 ...

  8. c语言共享内存,在爷儿俩进程间使用共享内存(共享内容含指针)

    在父子进程间使用共享内存(共享内容含指针) 比如有这样一个结构体 #define MAX_QUE_LEN 100 //定义数据包缓存队列 typedef struct _t_pkt_queue { U ...

  9. Linux进程间的通信----->共享内存

    共享内存:         顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进程之间共享的内存通常安排为同一段物 ...

最新文章

  1. NYOJ-49 开心的小明
  2. 实现做出html的上标以及下标
  3. Eclipse配置外部Tomcat
  4. 喜大普奔!Github 移动端上架!
  5. 信息学奥赛一本通 1096:数字统计 | 1949:【10NOIP普及组】数字统计 | OpenJudge NOI 1.5 41
  6. 2017.8.14 文本生成器 失败总结
  7. ES6系列:什么是ES6? 新手应该怎么理解
  8. Android:通过Intent传递对象、Parcelable
  9. python 并发编程 多线程 守护线程
  10. 能力提升综合题单 Part 8.7 图的连通性相关
  11. multism中ui和uo应该怎么表示_Multisim中节点如何标记
  12. ssh安装与配置(详解版)
  13. 免费开放的电子图书馆
  14. Ubuntu安装eog遇到的坑及解决方案
  15. UVA11991 Easy Problem from Rujia Liu?(第K个V的位置)
  16. 解决Maven Not Authorized问题
  17. 只做了delete操作,为啥 ORACLE-01466表定义已更改
  18. Python练习题——站队顺序输出
  19. web.py应用工具库:webpyext
  20. Java家庭记账程序

热门文章

  1. bypass最新版d盾mysql_Bypass D盾_IIS防火墙SQL注入防御(多姿势) | CN-SEC 中文网
  2. Ultra-QuickSort(离散化)
  3. BP神经网络基础知识(前向传播和后向传播)
  4. MATLAB信号处理之常用信号的表示(2)
  5. angularjs获取php数据类型,利用Angularjs从PHP读取后台数据
  6. OpenJDK和Java API区别_Linux下的JDK和OpenJDK有什么具体的区别
  7. c语言位运算测试题及答案,[原创] 位运算和bit位操作程序题目答案 -- 谭浩强C语言习题...
  8. java logfaction_Java8 下 重构log
  9. centos7 dotnet command not found
  10. 前端传递数据超过2M不能传给后台