linux c多进程通信之共享内存和信号量

编译环境:Ubuntu16.04 64位
交叉编译工具:arm-hisiv500-linux-gcc

文章目录

  • 1. 项目背景
  • 2. 涉及的函数
  • 3. 头文件JShm.h
  • 4. 类的实现
  • 5. sample代码

1. 项目背景

最近项目中需要用到共享内存的交互,取走旧数据,取数据不及时写入覆盖旧数据,队列长度可配置,自己造个轮子吧,对照下一篇linux c多线程简单队列实现。

2. 涉及的函数

详细描述可以百度或ubuntu下查询man手册。
共享内存相关:
int shmget(key_t key, size_t size, int shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

信号量相关:
int semget(key_t key,int nsems,int semflg);
int semctl(int semid,int semnum,int cmd, /union semun arg/);
semctl是可变参数长度的函数
int semop(int semid, struct sembuf *sops, size_t nsops);

3. 头文件JShm.h

#ifndef __J_SHM__
#define __J_SHM__#ifdef __cplusplus
extern "C" {
#endiftypedef enum _JShm_ERR{JSHM_NO_DATA = -4,				// 无数据供读取JSHM_READ_LENGTH_ERR = -3,		// 读取缓冲区长度不够JSHM_WRITE_LENGTH_ERR = -2,	// 写入共享内存长度超出JSHM_INIT_FAIL = -1,			// 初始化异常JSHM_OK = 0,JSHM_WRITE_OVERWRITE = 1,		// 写成功,但是覆盖
}JShm_ERR;class JShm {
public:JShm(int key, unsigned int size, unsigned int blockNum = 0);~JShm();int Write(unsigned char *buf, unsigned int len);int Read(unsigned char *buf, unsigned int len);private:int Init();int UnInit();int SemP();int SemV();static unsigned int IsPower2(unsigned int size);	static unsigned int To2N(unsigned int size);
private:int m_shmKey;unsigned int m_size;		// 共享内存大小unsigned int m_blockSize;	// 块大小unsigned int m_blockNum;	// 块数量unsigned char *m_buffer; 	// 共享内存地址unsigned int m_offset;		// 数据偏移量int m_shmID;int m_semID;
};#ifdef __cplusplus
}
#endif
#endif // __J_SHM__

4. 类的实现

#include <errno.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>#include "JShm.h"union SemUnion {int val;struct semid_ds *buf;
};struct ShmHead {unsigned int readPos;	// 读取位置,从0开始,blockNum不为0时有效unsigned int dataNum;	// 数据数量unsigned int len[0];	// 数据长度,根据blockNum分配
};unsigned int JShm::IsPower2(unsigned int size)
{if (size == 0)return 0;return ((size & (size - 1)) == 0);
}unsigned int JShm::To2N(unsigned int size)
{unsigned int i = 1;unsigned int tmp = size;while (size >>= 1){i <<= 1;}return (i < tmp) ? i << 1 : i;
}// 构造时,请务必保证双方的参数相同
// blockNum默认为0,不传时表示只有1块无缓存
JShm::JShm(int key, unsigned int blockSize, unsigned int blockNum)
{m_shmKey = key;unsigned int nSize = IsPower2(blockSize) ? blockSize : To2N(blockSize);m_blockSize = nSize;m_blockNum = (blockNum == 0) ? 1 : blockNum;m_offset = sizeof(ShmHead) + sizeof(unsigned int) * m_blockNum;m_size = m_blockSize * m_blockNum + m_offset;m_buffer = NULL;m_shmID = -1;m_semID = -1;Init();
}JShm::~JShm()
{UnInit();
}int JShm::Init()
{m_shmID = shmget(m_shmKey, m_size, IPC_CREAT | IPC_EXCL | 0666);if (m_shmID < 0){if (errno != EEXIST){return JSHM_INIT_FAIL;}m_shmID = shmget(m_shmKey, m_size, IPC_CREAT | 0666);if (m_shmID < 0){m_shmID = shmget(m_shmKey, 0, 0666);if (m_shmID < 0){return JSHM_INIT_FAIL;}if (shmctl(m_shmID, IPC_RMID, NULL)!= 0){return JSHM_INIT_FAIL;}m_shmID = shmget(m_shmKey, m_size, IPC_CREAT | IPC_EXCL | 0666);if (m_shmID < 0){return JSHM_INIT_FAIL;}}}m_buffer = (unsigned char *)shmat(m_shmID, NULL, 0);if (m_buffer == (unsigned char *)-1){return JSHM_INIT_FAIL;}memset(m_buffer, 0, m_size);m_semID = semget(m_shmKey, 1, 0666 | IPC_CREAT);if (m_semID < 0){return JSHM_INIT_FAIL;}union SemUnion semUnion;semUnion.val = 1;semctl(m_semID, 0, SETVAL, semUnion);return JSHM_OK;
}int JShm::UnInit()
{shmdt(m_buffer);m_buffer = NULL;shmctl(m_shmID, IPC_RMID, NULL);m_shmID = -1;semctl(m_semID, 0, IPC_RMID);m_semID = -1;return JSHM_OK;
}int JShm::SemP()
{// 申请信号,信号量-1sembuf semP;semP.sem_num = 0;semP.sem_op = -1;semP.sem_flg = SEM_UNDO;semop(m_semID, &semP, 1);return JSHM_OK;
}int JShm::SemV()
{// 释放信号,信号量+1sembuf semV;semV.sem_num = 0;semV.sem_op = 1;semV.sem_flg = SEM_UNDO;semop(m_semID, &semV, 1);return JSHM_OK;
}// !!!note:写入共享内存,写入长度需要小于等于块长度
// buf:要写入的数据
// len:要写入的数据的长度
// 返回值:>=0表示成功,0成功,1覆盖旧数据,-1表示失败
int JShm::Write(unsigned char *buf, unsigned int len)
{if (m_buffer == NULL)return JSHM_INIT_FAIL;if (len > m_blockSize)return JSHM_WRITE_LENGTH_ERR;	int ret = JSHM_OK;SemP();ShmHead *head = (ShmHead *)m_buffer;	unsigned int writePos = head->readPos + head->dataNum;if (writePos >= m_blockNum)writePos = writePos - m_blockNum;memcpy(m_buffer + m_offset + m_blockSize * writePos, buf, len);head->len[writePos] = len;if (head->dataNum == m_blockNum) // 满的{head->readPos = (writePos + 1 >= m_blockNum) ? 0 : writePos + 1;ret = JSHM_WRITE_OVERWRITE;}else{head->dataNum = head->dataNum + 1;}SemV();return ret;
}// !!!note:读取共享内存,读取长度需要大于等于数据长度
// buf:读数据的缓冲区
// len:缓冲区的长度
// 返回值:实际读取到的长度,<=0表示失败
int JShm::Read(unsigned char *buf, unsigned int len)
{if (m_buffer == NULL)return JSHM_INIT_FAIL;int ret = JSHM_OK;SemP();ShmHead *head = (ShmHead *)m_buffer;if (head->dataNum == 0){SemV();return JSHM_NO_DATA;}unsigned int readPos = head->readPos;if (len < head->len[readPos]){SemV();	return JSHM_READ_LENGTH_ERR;}memcpy(buf, m_buffer + m_offset + m_blockSize * readPos, head->len[readPos]);ret = head->len[readPos];head->readPos = (readPos + 1 >= m_blockNum) ? 0 : readPos + 1;head->dataNum = head->dataNum - 1;SemV();return ret;
}

5. sample代码

#include <stdio.h>#define SHM_KEY   101
#define SHM_BLOCKSIZE  1024
#define SHM_BLOCKNUM 2
int main(int argc, char* argv[])
{if (argc < 2){return -1;}if (argv[1][0] == 'w'){JShm *ShmWrite = new JShm(SHM_KEY, SHM_BLOCKSIZE, SHM_BLOCKNUM);while (true){char writeBuf[128] = {0};fgets(writeBuf, sizeof(writeBuf), stdin);if (writeBuf[0] == 'q'){delete ShmWrite;return 0;}printf("write data:%s\n", writeBuf);ShmWrite->Write((unsigned char *)writeBuf, strlen(writeBuf));}} else if (argv[1][0] == 'r') {JShm *ShmRead = new JShm(SHM_KEY ,SHM_BLOCKSIZE, SHM_BLOCKNUM);while (true) {char writeBuf[128] = {0};fgets(writeBuf, sizeof(writeBuf), stdin);if (writeBuf[0] == 'q'){delete ShmRead;return 0;}unsigned char readBuf[128] = { 0 };int ret = ShmRead->Read(readBuf, 127);printf("read %d data:%s\n", ret, readBuf);}}return 0;
}

编译完成之后,ubuntu下分别执行./a.out w和./a.out r测试。

以上。
转载请注明出处,如有错漏之处,敬请指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/812778.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MQ概览及Kafka详解

文章目录 概览MQ优点MQ缺点常见MQ对比JMS消息模型点对点模式发布订阅模式 kafka基础架构发布订阅工作流程生产者生产者文件存储生产者分区策略生产者数据可靠性保证生产者数据一致性保证生产者ack机制ExactlyOnce生产者发送消息流程 消费者消费者分区分配策略消费者消费数据问题…

算法设计与分析实验报告c++实现(TSP问题、哈夫曼编码问题、顾客安排问题、最小生成树问题、图着色问题)

一、实验目的 1&#xff0e;加深学生对贪心算法设计方法的基本思想、基本步骤、基本方法的理解与掌握&#xff1b; 2&#xff0e;提高学生利用课堂所学知识解决实际问题的能力&#xff1b; 3&#xff0e;提高学生综合应用所学知识解决实际问题的能力。 二、实验任务 用贪心算…

streamlit 大模型前段界面

结合 langchain 一起使用的工具&#xff0c;可以显示 web 界面 pip install streamlit duckduckgo-search 运行命令 streamlit run D:\Python_project\NLP\大模型学习\test.py import os from dotenv import load_dotenv from langchain_community.llms import Tongyi load…

基于springboot的大学城水电管理系统源码数据库

基于springboot的大学城水电管理系统源码数据库 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了大学城水电管理系统的开发全过程。通过分析大学城水电管理系统管理的不足&#xff0c;创建了一个计算机管理大学城水…

matlab学习002-函数及流程控制语句

目录 一&#xff0c;matlab编程基础 1&#xff09;matlab脚本和函数文件 ①脚本文件 ②函数文件 2&#xff09;函数的定义和调用 ①定义 ②调用 3&#xff09;程序流程控制 ①使用for求 122^2……2^622^63之和 ②使用while语句求122^2……2^622^63之和 ③使用matl…

Python学习(三)

函数扩展 多返回值 参数扩展 位置参数 注意:传递的参数和定义的参数的顺序及个数必须一致 关键字参数 关键字名称必须和形参名称相同&#xff0c;形参叫name&#xff0c;那么关键字也要写name 不定长参数 缺省参数

C语言奇技淫巧之--“函数指针数组”的类型定义与结构化初始化某一个函数

精力有限&#xff0c;就不写前言后序了&#xff0c;懂的都懂&#xff0c;直接上代码。 快速回忆点&#xff1a; # 类型定义 typedef int (*my_func_t)(int a, void *b)# 函数指针数组结构体定义 struct my_ops {int (*func[FUNC_TYPE_MAX])(int a, void *b); };# 函数指针数组…

Java8 Stream流的sorted()的排序【正序、倒序、多字段排序】

针对集合排序&#xff0c;java8可以用Stream流的sorted()进行排序。 示例Bean 以下我们会使用这个Bean来做示例。 public class Order {private String weight;private Double price;private String dateStr;//忽略getter、setter、构造方法、toString }字段排序 首先是比较器…

职场新员工倒挂老员工工资

职场的工资倒挂和工资构成 一个公司招新员工要开多少工资 主要取决于其他大厂出多少钱以及当年就业市场的行情。职场中常出现工资倒挂现象&#xff0c;即新员工的工资高于老员工。公司宁愿高薪招新员工而不给老员工加工资&#xff0c;主要是因为新员工的工资由市场决定&#…

【优选算法专栏】专题十:哈希表(一)

本专栏内容为&#xff1a;算法学习专栏&#xff0c;分为优选算法专栏&#xff0c;贪心算法专栏&#xff0c;动态规划专栏以及递归&#xff0c;搜索与回溯算法专栏四部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握算法。 &#x1f493;博主csdn个人主页&#xff1a;小…

[yotroy.cool]Haskell笔记一 —— 入门 算数 运算符 未定义变量 列表 字符串 类型

个人博客https://www.yotroy.cool/&#xff0c;欢迎关注我哦&#xff5e; 添加模块 ghci> :module Data.Ratio算数 - * / ** ^ % 基本的 ghci> 7.0 / 2.0 3.5 ghci> 7 / 2 3.5ghci> 2 2 4 ghci> () 2 2 4** 和 ^ - ** 可用于浮点数幂 ghci> 2.2**3.3 …

分治法python

分治法(Divide and Conquer)是一种重要的算法设计技巧,它将一个难以直接解决的问题分解成两个或更多的相同或相似的子问题,递归地解决这些子问题,然后将子问题的解组合起来,从而解决原问题。 以求最大值为例,假设我们有一个整数数组,我们想找到数组中的最大值。使用分…

mutable关键字的作用(c++)

常成员变量、常成员函数与常对象 常成员变量 声明为常成员变量的成员变量&#xff0c;在对象被创建后就不能被修改常成员变量必须在对象的构造函数初始化列表中赋值&#xff0c;不能在构造函数体中赋值初始化列表的执行是在函数体执行之前就执行了的。上面这种写法和下面的写…

卫星遥感影像在农业方面的应用及评价

一、引言 随着科技的进步&#xff0c;卫星遥感技术在农业领域的应用越来越广泛。卫星遥感技术以其宏观、快速、准确的特点&#xff0c;为农业生产和管理提供了有力的技术支撑。本文将对卫星遥感在农业方面的应用进行详细介绍&#xff0c;并通过具体案例进行说明。 二、…

(二)ffmpeg 下载安装以及拉流推流示例

一、ffmpeg下载安装 官网&#xff1a;https://www.ffmpeg.org/ 源码下载地址&#xff1a;https://www.ffmpeg.org/download.html#releases 下载源码压缩包 下载完成之后解压并在该目录下打开命令窗口 安装依赖环境&#xff1a; sudo apt-get install build-essential nasm …

【CAD建模号】学习笔记(二)——工作区

工作区介绍 工作区由[工具提示]&#xff0c;[自适应网格]&#xff0c;[自适应坐标轴]&#xff0c;[参考坐标轴]&#xff0c;[绘制的图形]组成。 一、工具提示 工具提示是提示当前工具的操作步骤&#xff0c;同时也提供了更加精确的参数输入方式建模、绘图时直接生成面&#x…

规则系统架构

规则系统架构 目录概述需求&#xff1a; 设计思路实现思路分析1.规则系统架构2. 规则系统架构优势 性能参数测试&#xff1a; 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,mak…

计算机常识

常见屏幕比例&#xff1a;16&#xff1a;9和16&#xff1a;10 分辨率&#xff1a;屏幕上水平和垂直方向的像素数量&#xff0c;决定了屏幕显示图像的细致程度和清晰度 简称 HD(High Definition)&#xff1a;高清 FHD(Full High Definition)&#xff1a;全高清 QHD (Quarter H…

Linux防止暴力破解密码脚本

1.认识记录linux记录安全的日志 [roottestpm ~]# cd /var/log/ [roottestpm log]# ls | grep secure secure 2.该日志的内容查看 [roottestpm log]# tail -f secure #表示ssh身份验证失败 Aug 29 23:35:03 testpm sshd[111245]: pam_unix(sshd:auth): authentication fa…

Java内存泄漏内存溢出

1.定义 OOM内存溢出是指应用程序尝试使用更多内存资源&#xff0c;而系统无足够的内存&#xff0c;导致程序崩溃。 内存泄漏是指应用程序中分配的内存未能被正确释放&#xff0c;导致系统中的可用内存逐渐减少。 2.内存泄漏的原因 可能包括对象引用未被释放、缓存未被清理等。 …