命名管道的实现与共享内存介绍

1.命名管道实现

comm.hpp文件

1.定义宏

通过宏来简便代码中,判断错误用宏就可以少写代码。

#define ERR_EXIT(m)         \do                      \{                       \perror(m);          \exit(EXIT_FAILURE); \} while (0)

在宏定义中使用 `do { ... } while (0)` 和不使用它的区别主要体现在**语句块的组合**和**控制流的安全性**上。以下是两者的详细对比,通过具体的例子来说明它们的区别。

---

### **1. 不使用 `do { ... } while (0)`**

假设我们定义一个宏,用于打印一条消息并退出程序:
```c
#define ERR_EXIT(msg) perror(msg); exit(EXIT_FAILURE);
```

#### **问题 1:控制流问题**
如果在 `if` 语句中使用这个宏:
```c
if (condition)
    ERR_EXIT("Error occurred");
else
    printf("Everything is fine.\n");
```

**展开后:**
```c
if (condition)
    perror("Error occurred"); exit(EXIT_FAILURE);
else
    printf("Everything is fine.\n");
```

**问题:**
- `else` 无法与 `if` 匹配,因为 `perror("Error occurred");` 和 `exit(EXIT_FAILURE);` 是两条独立的语句。
- 编译器会报错,因为 `else` 没有对应的 `if`。

#### **问题 2:链式调用问题**
如果尝试链式调用:
```c
ERR_EXIT("Error 1"); ERR_EXIT("Error 2");
```

**展开后:**
```c
perror("Error 1"); exit(EXIT_FAILURE); perror("Error 2"); exit(EXIT_FAILURE);
```

**问题:**
- `exit(EXIT_FAILURE);` 会导致程序立即退出,因此 `perror("Error 2");` 和第二个 `exit` 永远不会执行。
- 这种链式调用的意图无法实现。

---

### **2. 使用 `do { ... } while (0)`**

如果使用 `do { ... } while (0)` 重新定义宏:
```c
#define ERR_EXIT(msg) \
    do {              \
        perror(msg);  \
        exit(EXIT_FAILURE);\
    } while (0)
```

#### **优点 1:控制流安全**
在 `if` 语句中使用:
```c
if (condition)
    ERR_EXIT("Error occurred");
else
    printf("Everything is fine.\n");
```

**展开后:**
```c
if (condition)
    do { perror("Error occurred"); exit(EXIT_FAILURE); } while (0);
else
    printf("Everything is fine.\n");
```

**优点:**
- `do { ... } while (0)` 将多条语句组合成一个单一的语句块。
- `else` 能正确匹配 `if`,不会报错。

#### **优点 2:支持链式调用**
尝试链式调用:
```c
ERR_EXIT("Error 1"); ERR_EXIT("Error 2");
```

**展开后:**
```c
do { perror("Error 1"); exit(EXIT_FAILURE); } while (0);
do { perror("Error 2"); exit(EXIT_FAILURE); } while (0);
```

**优点:**
- 每个 `do { ... } while (0)` 是独立的语句块,不会相互干扰。
- 虽然程序会在第一个 `exit` 时退出,但这种结构不会导致语法错误。

---

### **3. 总结:有和没有的区别**

| 特性                | 不使用 `do { ... } while (0)` | 使用 `do { ... } while (0)` |
|---------------------|-------------------------------|----------------------------|
| **控制流安全性**     | 容易出错(`if-else` 问题)    | 安全(`if-else` 正常工作)  |
| **链式调用支持**     | 不支持(语句中断)            | 支持(语句块独立)          |
| **语句块完整性**     | 多条语句独立,易出错          | 多条语句组合成一个块,安全  |
| **调试难度**         | 调试时难以定位问题            | 调试时结构清晰,易于定位    |

---

### **4. 使用场景总结**

- **不使用 `do { ... } while (0)`**:适用于非常简单的宏,只包含一条语句(如 `#define MAX(a, b) ((a) > (b) ? (a) : (b))`)。
- **使用 `do { ... } while (0)`**:适用于复杂的宏,包含多条语句,需要确保宏像函数一样安全使用。

总之,`do { ... } while (0)` 是一种非常有用的技巧,可以显著提高宏的安全性和可维护性。

 2.管道文件类

定义一个类来管理文件,创建管道文件和初始化管道文件名,还有删除管道文件。

class NamedFifo
{
public:NamedFifo(const std::string& path,const std::string& name):_path(path),_name(name){_fifoname=_path+"/"+_name;umask(0);//新建管道int n =mkfifo(_fifoname.c_str(),0666);if(n<0){ERR_EXIT("mkfifo");}else{std::cout<<"mkfifo sucess"<<std::endl;}}~NamedFifo(){//删除管道文件int n=unlink(_fifoname.c_str());if(n==0){ERR_EXIT("unlink");}else{std::cout<<"remove fifo failed"<<std::endl;}}private:std::string _path;std::string _name;std::string _fifoname;
};

3.管道文件操作类

这个类虽然与前一个类大体相似,但主要是为client中看不到管道文件的路径,只要server知道,且加入了以读形式打开文件方法,写形式打开文件方法,写和读操作的方法。

class FileOper
{public:FileOper(const std::string& path,const std::string& name):_path(path),_name(name),_fd(-1){_fifoname=_path+"/"+_name;}void OpenForRead(){_fd=open(_fifoname.c_str(),O_RDONLY);if(_fd<0)ERR_EXIT("open");std::cout<<"open fifo sucess"<<std::endl;}void OpenForWrite(){_fd=open(_fifoname.c_str(),O_WRONLY);if(_fd<0)ERR_EXIT("open");std::cout<<"open fifo sucess"<<std::endl;}void Write(){std::string message;int cnt=1;pid_t id=getpid();while(true){std::cout<<"Please Enter#";std::getline(std::cin,message);message+=(",message number: "+std::to_string(cnt++)+", ["+std::to_string(id)+"]");write(_fd,message.c_str(),message.size());}}void Read(){while(true){char buffer[1024];int number=read(_fd,buffer,sizeof(buffer)-1);if(number>0){buffer[number]=0;std::cout<<"Client say#"<<buffer<<std::endl;}else if(number==0){std::cout<<"Client quit! me too!"<<std::endl;break;}else{std::cerr<<"read error"<<std::endl;break;}}}void Close(){if(_fd>0)close(_fd);}~FileOper() {}private:std::string _path;std::string _name;std::string _fifoname;int _fd;
};
#include "comm.hpp"int main()
{//创建管道文件NamedFifo fifo(PATH,FILENAME);FileOper readerfile(PATH,FILENAME);readerfile.OpenForRead();readerfile.Read();readerfile.Close();return 0;
}

server.cc文件

 

#include "comm.hpp"int main()
{//创建管道文件NamedFifo fifo(PATH,FILENAME);FileOper readerfile(PATH,FILENAME);readerfile.OpenForRead();readerfile.Read();readerfile.Close();return 0;
}

client.cc文件

 

#include "comm.hpp"int main()
{//创建管道文件NamedFifo fifo(PATH,FILENAME);FileOper readerfile(PATH,FILENAME);readerfile.OpenForRead();readerfile.Read();readerfile.Close();return 0;
}

Makefile文件

.PHONY:all
all:client server
client:client.ccg++ -o $@ $^ -std=c++11
server:server.ccg++ -o $@ $^ -std=c++11.PHONY:clean
clean:rm -f client server

2.system V共享内存

共享内存是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程数据传输不再涉及到内核,意思是进程不再通过执行进入内核的系统调用来传递彼此的数据。

共享内存示意图

俩个进程的进程地址空间都开辟一块共享区域,与物理内存上的step1形成映射关系通过页表,这样进程A在自己的进程地址空间读写操作,进程B的共享区也会发生改变。

 共享内存数据结构

共享内存函数

shmget函数

 

`shmget` 是 System V IPC(进程间通信)机制中的一个函数,用于创建新的共享内存段或获取已存在的共享内存段的标识符。以下是 `shmget` 的详细说明和用法:

### 函数原型
```c
int shmget(key_t key, size_t size, int shmflg);
```

### 参数说明
1. **`key_t key`**
   - 用于标识共享内存的键值,可以是以下几种情况:
     - **`IPC_PRIVATE`**:表示创建一个私有的共享内存段,仅对当前进程可见。
     - **大于 0 的整数**:通常由 `ftok` 函数生成的唯一键。
     - **`0`**:若与 `IPC_CREAT` 标志结合,同样会创建新的共享内存。

2. **`size_t size`**
   - 指定共享内存段的大小(以字节为单位)。实际分配时,系统会以页面大小为单位进行分配。

3. **`int shmflg`**
   - 控制共享内存的权限和行为,通常是一个权限标志(如 `0666`)与其他标志的组合:
     - **`IPC_CREAT`**:如果键值对应的共享内存不存在,则创建一个新的共享内存。
     - **`IPC_EXCL`**:与 `IPC_CREAT` 结合使用,如果共享内存已存在,则返回错误。

### 返回值
- 成功时返回共享内存的标识符(`shm_id`)。
- 失败时返回 `-1`,并设置 `errno` 以指示错误。

这里是key值来保证共享内存存在和俩个进程是对应同一个共享区,key值的唯一性来找到唯一的哪一个,ftok函数可以返回一个唯一的key值使用。

代码示例

comm.hpp文件

#pragma once#include <iostream>
#include <cstdio>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>const int gdefaultid=-1;
const int gsize=4096;
const std::string pathname=".";
const int projid=0x66;#define ERR_EXIT(m)         \do                      \{                       \perror(m);          \exit(EXIT_FAILURE); \} while (0)class Shm
{public:Shm():_shmid(gdefaultid),_size(gsize){}void Create(){key_t k=ftok(pathname.c_str(),projid);if(k<0){ERR_EXIT("ftok");}printf("key: 0x%X",k);_shmid=shmget(k,_size,IPC_CREAT|IPC_EXCL);if(_shmid<0)ERR_EXIT("shmget");printf("shmid: %d",_shmid);}~Shm(){}private:int _shmid;int _size;
};

 

server.cc文件

#include "comm.hpp"int main()
{Shm shm;shm.Create();return 0;
}

client.cc文件

#include "comm.hpp"int main()
{return 0;
}

 Makefile文件

.PHONY:all
all:client server
client:client.ccg++ -o $@ $^ -std=c++11
server:server.ccg++ -o $@ $^ -std=c++11.PHONY:clean
clean:rm -f client server

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

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

相关文章

Window下Redis的安装和部署详细图文教程(Redis的安装和可视化工具的使用)

文章目录 Redis下载地址&#xff1a;一、zip压缩包方式下载安装 1、下载Redis压缩包2、解压到文件夹3、启动Redis服务4、打开Redis客户端进行连接5、使用一些基础操作来测试 二、msi安装包方式下载安装 1、下载Redis安装包2、进行安装3、进行配置4、启动服务5、测试能否正常工…

哔哩哔哩IT私塾python爬虫视频教程中的项目文件

视频链接&#xff1a; Python课程天花板,Python入门Python爬虫Python数据分析5天项目实操/Python基础.Python教程_哔哩哔哩_bilibili 视频教程中要访问的链接&#xff1a; 豆瓣电影 Top 250 httpbin.org seo推广公司网站模板_站长素材 Examples - Apache ECharts WordCloud…

go前后端开源项目go-admin,本地启动

https://github.com/go-admin-team/go-admin 教程 1.拉取项目 git clone https://github.com/go-admin-team/go-admin.git 2.更新整理依赖 go mod tidy会整理依赖&#xff0c;下载缺少的包&#xff0c;移除不用的&#xff0c;并更新go.sum。 # 更新整理依赖 go mod tidy 3.编…

深入理解Spring @Async:异步编程的利器与实战指南

一、为什么需要异步编程&#xff1f; 在现代高并发系统中&#xff0c;同步阻塞式编程会带来两大核心问题&#xff1a; // 同步处理示例 public void processOrder(Order order) {// 1. 保存订单&#xff08;耗时50ms&#xff09;orderRepository.save(order); // 2. 发送短信…

PHP:IDEA开发工具配置XDebug,断点调试

文章目录 一、php.ini配置二、IDEA配置 一、php.ini配置 [xdebug] zend_extension"F:\wamp64\bin\php\php7.4.0\ext\php_xdebug-2.8.0-7.4-vc15-x86_64.dll" xdebug.remote_enable on xdebug.remote_host 127.0.0.1 xdebug.remote_port 9001 xdebug.idekey"…

FPGA开发,使用Deepseek V3还是R1(9):FPGA的全流程(详细版)

以下都是Deepseek生成的答案 FPGA开发&#xff0c;使用Deepseek V3还是R1&#xff08;1&#xff09;&#xff1a;应用场景 FPGA开发&#xff0c;使用Deepseek V3还是R1&#xff08;2&#xff09;&#xff1a;V3和R1的区别 FPGA开发&#xff0c;使用Deepseek V3还是R1&#x…

AtCoder Beginner Contest 001(A - 積雪深差、B - 視程の通報、C - 風力観測、D - 感雨時刻の整理)题目翻译

由于我发现网上很少有人会发很久之前AtCoder Beginner Contes的题&#xff0c;所以我打算从AtCoder Beginner Contest 001开始写。大约两周一更&#xff0c;需要的可以订阅专栏&#xff0c;感谢支持Thanks♪(&#xff65;ω&#xff65;)&#xff89; →题目讲解 A - 積雪深差 …

upload

&#xff08;上传一句话木马&#xff0c;用蚁剑链接验证是否成功/传有回显的&#xff1a;<?php phpinfo();?>&#xff09; 学看代码 #function checkfile(){}&#xff1a;定义了一个名叫checkfile的函数 #var file方法.(获取名为‘upload_file’的元素)[获取哪些&…

【漫话机器学习系列】110.线性可分(Linearly Separable)

线性可分与线性不可分的概念详解 1. 引言 在机器学习和模式识别领域&#xff0c;分类问题是一个重要的研究方向。在分类任务中&#xff0c;我们通常需要将不同类别的数据点分开&#xff0c;而如何进行分割是一个关键问题。线性可分&#xff08;Linearly Separable&#xff09…

5G学习笔记之BWP

我们只会经历一种人生&#xff0c;我们选择的人生。 参考&#xff1a;《5G NR标准》、《5G无线系统指南:如微见著&#xff0c;赋能数字化时代》 目录 1. 概述2. BWP频域位置3. 初始与专用BWP4. 默认BWP5. 切换BWP 1. 概述 在LTE的设计中&#xff0c;默认所有终端均能处理最大2…

在笔记本电脑上用DeepSeek搭建个人知识库

最近DeepSeek爆火&#xff0c;试用DeepSeek的企业和个人越来越多。最常见的应用场景就是知识库和知识问答。所以本人也试用了一下&#xff0c;在笔记本电脑上部署DeepSeek并使用开源工具搭建一套知识库&#xff0c;实现完全在本地环境下使用本地文档搭建个人知识库。操作过程共…

【实战 ES】实战 Elasticsearch:快速上手与深度实践-1.2.2倒排索引原理与分词器(Analyzer)

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 1.2.2倒排索引原理与分词器&#xff08;Analyzer&#xff09;1. 倒排索引&#xff1a;搜索引擎的基石1.1 正排索引 vs 倒排索引示例数据对比&#xff1a; 1.2 倒排索引核心结…

计算机毕业设计SpringBoot+Vue.js线上辅导班系统(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

大模型原理与技术(毛玉仁)

一、基础知识 ①基于统计的语言模型&#xff1a;n-gram&#xff0c;基于前n-1个词预测第当前词&#xff0c;即统计词序个数计算概率&#xff08;n阶马尔科夫&#xff09;。如果预测句子的概率&#xff0c;需要将每个分词连乘。 常用的n小于5&#xff0c;随着n增大&#xff0c;…

ollama本地部署DeepSeek-R1大模型使用前端JS调用的详细流程

以下是关于如何在本地部署 DeepSeek-R1 大模型&#xff08;通过 Ollama&#xff09;&#xff0c;并使用前端 JavaScript 调用其功能的详细流程。 前提条件 硬件要求&#xff1a; 建议至少 16GB RAM&#xff08;运行较小模型如 1.5B 或 7B 参数版本&#xff09;&#xff0c;如果…

最好Wordpree+Apache+PHP安装教程

前提需要 PHP的安装最少需要7.4以上Mysql的安装&#xff0c;直接默认最新版就行APache服务器&#xff08;HTTP服务器&#xff0c;只有用这个你的软件才能在服务器上运行&#xff09; 安装apache 安装 sudo apt install apache2查看防火墙 sudo ufw app list如果有 Apache那…

deepseek使用记录18——文化基因之文化融合

文明长河中的生命浪花 在洛阳白马寺的银杏树下&#xff0c;年轻母亲指着"农禅并重"碑刻给孩子讲述祖辈耕作的故事&#xff1b;在哔哩哔哩的直播间里&#xff0c;00后女孩穿着汉服跳起街舞&#xff0c;弹幕飘过"这才是文化缝合怪"。当文明交融的宏大叙事照…

2025 GDC开发者先锋大会“人形机器人的开源之路”分论坛 | 圆桌会议:《开放协作:开源生态如何解锁人形机器人与具身智能的未来》(上篇)

在GDC全球开发者先锋大会期间&#xff0c;2月23日&#xff0c;由GDC组委会指导、国家地方共建人形机器人创新中心&#xff08;以下简称“国地中心”&#xff09;承办的“人形机器人的开源之路”主题论坛在上海西岸艺术中心成功举办。 在人工智能与机器人技术飞速发展的今天&…

txt 转 json 使用python语言

需求: 把如下的txt文档转成json输出 代码 import jsondef txt_to_json(input_file, output_file):data_list []with open(input_file, r, encodingutf-8) as f:for line in f:# 分割数据并去除换行符parts line.strip().split(,)print(f"{parts}")print(type(par…

快速入手-搭建Flask框架封装mysql并结合业务实际情况使用

1、安装包 pip install pymysql pip install dbutils 2、项目目录结构&#xff0c;注意目录的层级 3、在flask_project文件夹里创建__init__.py from flask import Flask, redirect, request, session def auth():# 拦截器print("拦截器")# js、css、img不拦截处…