pipe匿名管道實操(Linux)

管道相關函數

1 pipe

  • 是 Unix/Linux 系統中的一個系統調用,用于創建一個匿名管道
#include <unistd.h>
int pipe(int pipefd[2]);
參數說明:
pipefd[2]:一個包含兩個整數的數組,用于存儲管道的文件描述符:
pipefd[0]:管道的讀端(用于從管道讀取數據)巧記:用嘴巴口型(o)讀
pipefd[1]:管道的寫端(用于向管道寫入數據)巧記:用筆(1)寫
返回值:
成功時返回 0
失敗時返回 -1 并設置 errno

2 error

errno?是 C 和 C++ 中用于報告錯誤的全局變量(或宏),全稱為 "error number"。它由系統或標準庫函數在操作失敗時設置,用于指示具體的錯誤原因。代碼出錯時我們更想知道出錯原因,就可以用error

常見?errno?錯誤碼

錯誤碼宏含義
EPERM1操作無權限
ENOENT2文件或目錄不存在
EINTR4系統調用被中斷
EIO5輸入/輸出錯誤
EBADF9錯誤的文件描述符
EAGAIN11資源暫時不可用
ENOMEM12內存不足
EACCES13權限不足
EFAULT14非法內存訪問
EEXIST17文件已存在
EDOM33數學參數超出定義域
ERANGE34結果超出范圍

一般和和strerror配合一起使用?

#include <iostream>
#include <cerrno>  
#include <cstring>int main() {errno = 0; // 先重置 errnodouble x = sqrt(-1.0); // 嘗試計算負數的平方根if (errno == EDOM) {   // EDOM 是域錯誤宏std::cerr << "Error: " << std::strerror(errno) << "\n";}
}
輸出:
Error: Numerical argument out of domain

3 strerror?

  • ?是 C 標準庫中的一個函數,用于將錯誤代碼(errno 值)轉換為可讀的錯誤描述字符串。下面我會詳細解釋它的用法和實際應用場景。
#include <string.h>  
char *strerror(int errnum);
參數說明:
errnum:錯誤編號(通常是 errno 的值)
返回值:
返回指向錯誤描述字符串的指針(靜態分配的字符串,不可修改)
不會失敗(永遠返回有效指針)

4 推薦使用?#include <cerrno>?而不是?#include <errno.h>


1.?符合 C++ 標準庫的命名規范

C++ 標準庫對 C 標準庫的頭文件進行了重新封裝,采用無?.h?后綴的形式(如?<cstdio><cstdlib><cerrno>),以區別于 C 的傳統頭文件(如?<stdio.h>stdlib.herrno.h>)。

  • <cerrno>?是 C++ 標準化的頭文件,明確屬于 C++ 標準庫。
  • <errno.h>?是 C 風格的頭文件,雖然 C++ 兼容它,但不推薦在新代碼中使用。

2.?潛在的命名空間管理

理論上,<cerrno>?將相關名稱(如?errnoEDOMERANGE)放入?std?命名空間,而?<errno.h>?直接將它們暴露在全局命名空間。雖然實際實現中(由于兼容性要求):

  • errno?仍然是全局宏(無法放入?std)。
  • EDOMERANGE?等宏通常在全局命名空間也可用。

但使用?<cerrno>?能更清晰地表達“這是 C++ 代碼”的意圖,并可能在未來的標準中更好地支持命名空間隔離。


注意事項

  • errno?仍是全局宏:即使使用?<cerrno>errno?也不會變成?std::errno(因為它是宏)。
  • 錯誤碼宏(如?EDOM:大多數實現仍允許全局訪問,但理論上可以額外通過?std::EDOM?訪問(盡管實踐中很少需要)。

5?fork()?系統調用詳解

  • fork()?是 Unix/Linux 系統中的一個重要系統調用,用于創建一個新的進程(子進程)
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
返回值:
父進程:返回子進程的?PID(進程ID,> 0)。
子進程:返回?0。
出錯時:返回?-1(并設置?errno)。

6 exit

  • 是一個標準庫函數,用于終止當前進程,并返回一個狀態碼給操作系統。它是進程正常退出的標準方式
#include <stdlib.h>
void exit(int status);
參數:
status:進程的退出狀態碼:
0 或 EXIT_SUCCESS:表示成功退出。
非零值(通常 EXIT_FAILURE=1):表示失敗退出(具體含義由程序定義)

exit()?的運行機制

(1) 進程終止流程

當調用?exit()?時,操作系統會按順序執行以下操作:

  1. 調用?atexit()?注冊的函數(按注冊的逆序執行)。

  2. 刷新所有標準 I/O 緩沖區(如?printf?未輸出的內容會被強制寫入)。

  3. 關閉所有打開的文件描述符

  4. 釋放進程占用的內存和其他資源

  5. 向父進程發送狀態碼(可通過?wait()?或?$??獲取)。

(2)?exit()?vs?_exit()

函數說明
exit()標準 C 庫函數,會執行清理(刷新緩沖區、調用?atexit()?等)。
_exit()系統調用(<unistd.h>),直接終止進程,不執行任何清理

?7?snprintf?

snprintf?是 C 標準庫中的一個格式化輸出函數,用于安全地格式化字符串并寫入緩沖區,比傳統的?sprintf?更安全,因為它可以防止緩沖區溢出(Buffer Overflow)

#include <stdio.h>
int snprintf(char *str,       // 目標緩沖區size_t size,     // 緩沖區大小(最多寫入 size-1 個字符 + '\0')const char *format,  // 格式化字符串(類似 printf)...              // 可變參數(要格式化的數據)
);
返回值:
成功:返回理論寫入的字符數(不包括結尾的?\0),即使緩沖區不夠。
錯誤:返回負值(如編碼錯誤)。

    8?getpid()??getppid()

    • getpid()?是 Unix/Linux 系統編程中的一個基礎系統調用,用于獲取當前進程的進程ID(PID)
    • getppid()?是 Unix/Linux 系統調用,用于獲取當前進程的父進程 PID(Process ID)
    #include <unistd.h>  // 必須包含的頭文件
    pid_t getpid(void);  // 返回當前進程的 PID
    返回值:
    成功:返回當前進程的?PID(正整數)
    不會失敗(無錯誤碼)#include <unistd.h>  // 必須包含的頭文件
    pid_t getppid(void); // 返回父進程的 PID
    返回值:
    成功:返回父進程的 PID(正整數)
    不會失敗(無錯誤碼)

    9?sizeof?

    sizeof?是 C/C++ 中的一個編譯時運算符(不是函數!),用于計算變量、類型或表達式所占的內存大小(字節數)。它是靜態計算的,不會在運行時影響程序性能

    sizeof(變量或類型)
    返回值:
    size_t 類型的無符號整數(通常是 unsigned int 或 unsigned long)。
    計算時機:在編譯時確定,不會執行括號內的代碼(如果傳入表達式)

    語法規則

    操作對象示例是否必須加括號備注
    變量名sizeof a可選更簡潔,但可能降低可讀性
    類型名sizeof(int)必須不加括號會導致編譯錯誤
    表達式sizeof(a + b)必須表達式需用括號包裹

    示例?

    int arr[10];變量(括號可選)
    size_t s1 = sizeof arr;     // 計算數組總大小
    size_t s2 = sizeof(arr);    // 等效寫法類型(括號必須)
    size_t s3 = sizeof(int);    // 計算 int 類型大小表達式(括號必須)
    size_t s4 = sizeof(arr[0]); // 計算數組元素大小結構體/類成員的大小
    struct S { int x; double y; };
    size_t s = sizeof(S::x);  // C++ 中合法,計算成員大小

    創建管道實操

    makefile

    mypipe:mypipe.ccg++ -o $@ $^ -std=c++11
    .PHONY:clean
    clean:rm -rf mypipe

    mypipe.cc

    #include <iostream>
    #include <string>
    #include <cerrno>
    #include <cassert>
    #include <string.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/wait.h>int main()
    {int pipefd[2] = {0};int n = pipe(pipefd);if(n < 0){std::cout << "pipe error, " << errno << ": " << strerror(errno) << std::endl;return 1;}pid_t id = fork();assert(id != -1); if(id == 0){close(pipefd[0]);int cnt = 0;while(true){char x = 'X';write(pipefd[1], &x, 1);std::cout << "Cnt: " << cnt++<<std::endl;sleep(1);}close(pipefd[1]);exit(0);}close(pipefd[1]);char buffer[1024];int cnt = 0;while(true){int n = read(pipefd[0], buffer, sizeof(buffer) - 1);if(n > 0){buffer[n] = '\0';std::cout << "我是父進程, child give me message: " << buffer << std::endl;}else if(n == 0){std::cout << "我是父進程, 讀到了文件結尾" << std::endl;break;}else {std::cout << "我是父進程, 讀異常了" << std::endl;break;}sleep(1);if(cnt++ > 5) break;}close(pipefd[0]);int status = 0;waitpid(id, &status, 0);std::cout << "sig: " << (status & 0x7F) << std::endl;sleep(100);return 0;
    }

    ?

    • mypipe:目標文件(可執行文件)名稱
    • mypipe.cc:依賴文件(源代碼文件)
    • g++ -o $@ $^ -std=c++11:編譯命令
      • $@?表示目標文件(mypipe)
      • $^?表示所有依賴文件(這里只有 mypipe.cc)
      • -std=c++11?指定使用 C++11 標準
    • .PHONY:clean:聲明 clean 是一個偽目標(不是實際文件)
    • rm -rf mypipe:刪除生成的可執行文件

    父進程管理多個子進程實現管道通信實操

    Makefile

    ctrlProcess:ctrlProcess.ccg++ -o $@ $^ -std=c++11
    .PHONY:clean
    clean:rm -rf ctrlProcess
    

    Task.hpp

    #pragma once#include <iostream>
    #include <vector>
    #include <unistd.h>typedef void (*fun_t)(); void a() { std::cout << "a任務正在執行...\n" << std::endl; }
    void b() { std::cout << "b任務正在執行...\n" << std::endl; }
    void c() { std::cout << "c任務正在執行...\n" << std::endl; }#define A 0
    #define B 1
    #define C 2class Task
    {
    public:Task(){funcs.push_back(a);funcs.push_back(b);funcs.push_back(c);}void Execute(int command){if (command >= 0 && command < funcs.size()) funcs[command]();}public:std::vector<fun_t> funcs;
    };

    ctrlProcess.cc

    #include <iostream>
    #include <string>
    #include <vector>
    #include <cassert>
    #include <unistd.h>
    #include <sys/wait.h>
    #include <sys/types.h>
    #include "Task.hpp"
    using namespace std;const int gnum = 3;
    Task t;class EndPoint
    {
    private:static int number;
    public:pid_t _c_id;int _w_fd;string processname;
    public:EndPoint(int id, int fd) :_c_id(id), _w_fd(fd){//process-0[pid:fd]char namebuffer[64];snprintf(namebuffer, sizeof(namebuffer), "process-%d[%d:%d]", number++, _c_id, _w_fd);processname = namebuffer;}string name() const { return processname; }
    };int EndPoint::number = 0;void WaitCommand()
    {while(1){int command = 0;int n = read(0, &command, sizeof(command));if (n == sizeof(int)) t.Execute(command);else if (n == 0){std::cout << "父進程關閉了寫端" << getpid() << std::endl;break;}else break;}
    }void createProcesses(vector<EndPoint> *end_points)
    {vector<int> fds;for(int i = 0; i < gnum; ++i){int pipefd[2] = {0};int n = pipe(pipefd);assert(n == 0); (void)n;pid_t id = fork();assert(id != -1);if (id == 0){for(auto &fd : fds) close(fd);close(pipefd[1]);dup2(pipefd[0], 0);WaitCommand();close(pipefd[0]);exit(0);}close(pipefd[0]);end_points->push_back(EndPoint(id, pipefd[1]));fds.push_back(pipefd[1]);}
    }int ShowBoard()
    {std::cout << "##########################################" << std::endl;std::cout << "|   0. 執行日志任務   1. 執行數據庫任務    |" << std::endl;std::cout << "|   2. 執行請求任務   3. 退出             |" << std::endl;std::cout << "##########################################" << std::endl;std::cout << "請選擇# ";int command = 0;std::cin >> command;return command;
    }void ctrlProcess(const vector<EndPoint> &end_points)
    {int cnt = 0;while(true){int command = ShowBoard();if (command == 3) break;if (command < 0 || command > 2) continue;int index = cnt++;cnt %= end_points.size();string name = end_points[index].name();cout << "選擇了進程: " <<  name << " | 處理任務: " << command << endl;write(end_points[index]._w_fd, &command, sizeof(command));sleep(1);}
    }void waitProcess(const vector<EndPoint> &end_points)
    {for(int i = 0; i < end_points.size(); ++i){std::cout << "父進程讓子進程退出:" << end_points[i]._c_id << std::endl;close(end_points[i]._w_fd);waitpid(end_points[i]._c_id, nullptr, 0);std::cout << "父進程回收了子進程:" << end_points[i]._c_id << std::endl;}
    }// #define A 0
    // #define B 1
    // #define C 2int main()
    {vector<EndPoint> end_points;createProcesses(&end_points);ctrlProcess(end_points);waitProcess(end_points);return 0;
    }

    本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
    如若轉載,請注明出處:http://www.pswp.cn/pingmian/76440.shtml
    繁體地址,請注明出處:http://hk.pswp.cn/pingmian/76440.shtml
    英文地址,請注明出處:http://en.pswp.cn/pingmian/76440.shtml

    如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

    相關文章

    centos-stream-9上安裝nvidia驅動和cuda-toolkit

    這里寫目錄標題 驅動安裝1. 更新系統2. NVIDIA GPU安裝檢查系統是否安裝了 NVIDIA GPU2.1 首先&#xff0c;使用以下命令更新 DNF 軟件包存儲庫緩存&#xff1a;2.2 安裝編譯 NVIDIA 內核模塊所需的依賴項和構建工具2.3 在 CentOS Stream 9 上添加官方 NVIDIA CUDA 軟件包存儲庫…

    LDAP高效數據同步:Syncrepl復制模式實戰指南

    #作者&#xff1a;朱雷 文章目錄 一、Syncrepl 復制簡介1.1. 什么是復制模式1.2. 什么是 syncrepl同步復制 二、Ldap環境部署三、配置復制類型3.1. 提供者端配置3.2. 消費者端配置3.3.啟動服務3.4.測試同步是否生效 四、總結 一、Syncrepl 復制簡介 1.1. 什么是復制模式 Ope…

    Linux 內核網絡協議棧中的 struct packet_type:以 ip_packet_type 為例

    在 Linux 內核的網絡協議棧中,struct packet_type 是一個核心數據結構,用于注冊特定協議類型的數據包處理邏輯。它定義了如何處理特定協議的數據包,并通過協議類型匹配機制實現協議分發。本文將通過分析 ip_packet_type 的定義和作用,深入探討其在網絡協議棧中的重要性。 …

    QT Sqlite數據庫-教程001 創建數據庫和表-下

    【1】創建帶名稱的數據庫 #include <QtSql/QSqlDatabase> #include <QtSql/QSqlQuery> #include <QtSql/QSqlRecord> QString path QDir::currentPath(); QApplication::addLibraryPath(pathQString("/release/plugins")); QPluginLoader loader…

    Cannot find module ‘vue‘ or its corresponding type declarations

    在使用vue3vite創建新的工程時&#xff0c;在新增.vue文件時會出現Cannot find module vue這個錯誤。 只需要我們在項目中的.d.ts文件中添加以下代碼即可 declare module *.vue {import { defineComponent } from vue;const component: ReturnType<typeof defineComponent&…

    SSRF打靶總結

    文章目錄 一. PortSwigger1、本地服務器的基本SSRF2、基本的目標不是漏洞機3、Referer標頭的外帶SSRF4、簡單黑名單的SSRF黑名單繞過思路&#xff1a; 5、重定向的SSRF6. 簡單的白名單SSRF白名單繞過思路&#xff1a; 二、BWAPP1. SSRF 文件包含漏洞 | 內網探測2. XXE -> S…

    STL-函數對象

    1.函數對象 1.1 概念 重載函數調用操作符的類&#xff0c;其對象被稱為函數對象 函數對象使用重載的&#xff08;&#xff09;時&#xff0c;行為類似函數調用&#xff0c;也成為仿函數 本質&#xff1a;函數對象&#xff08;仿函數&#xff09;是一個類&#xff0c;不是一…

    多線程(Java)

    注&#xff1a;本文為本人學習過程中的筆記 1.導入 1.進程和線程 我們希望我們的程序可以并發執行以提升效率&#xff0c;此時引入了多進程編程。可是創建進程等操作開銷太大&#xff0c;于是就將進程進一步拆分成線程&#xff0c;減少開銷。進程與進程之間所涉及到的資源是…

    在 Dev-C++中編譯運行GUI 程序介紹(三)有趣示例一組

    在 Dev-C中編譯運行GUI程序介紹&#xff08;三&#xff09;有趣示例一組 前期見 在 Dev-C中編譯運行GUI 程序介紹&#xff08;一&#xff09;基礎 https://blog.csdn.net/cnds123/article/details/147019078 在 Dev-C中編譯運行GUI 程序介紹&#xff08;二&#xff09;示例&a…

    【高校主辦】2025年第四屆信息與通信工程國際會議(JCICE 2025)

    重要信息 會議網址&#xff1a;www.jcice.org 會議時間&#xff1a;2025年7月25-27日 召開地點&#xff1a;哈爾濱 截稿時間&#xff1a;2025年6月15日 錄用通知&#xff1a;投稿后2周內 收錄檢索&#xff1a;EI,Scopus 會議簡介 JCICE 2022、JCICE 2023、JCICE 2…

    【Linux】Linux 操作系統 - 03 ,初步指令結尾 + shell 理解

    文章目錄 前言一、打包和壓縮二、有關體系結構 (考)面試題 三、重要的熱鍵四、shell 命令及運行原理初步理解五、本節命令總結總結 前言 本篇文章 , 筆者記錄的筆記內容包含 : 基礎指令 、重要熱鍵 、shell 初步理解 、權限用戶的部分問題 。 內容皆是重要知識點 , 需要認真理…

    Python: sqlite3.OperationalError: no such table: ***解析

    出現該錯誤說明數據庫中沒有成功創建 reviews 表。以下是完整的解決方案: 步驟 1:創建數據庫表 在插入數據前,必須先執行建表語句。請通過以下任一方式創建表: 方式一:使用 SQLite 命令行 bash 復制 # 進入 SQLite 命令行 sqlite3 reviews.db# 執行建表語句 CREATE T…

    VSCode CLine 插件自定義配置使用 Claude 3.7 模型進行 AI 開發

    一個互聯網技術玩家&#xff0c;一個愛聊技術的家伙。在工作和學習中不斷思考&#xff0c;把這些思考總結出來&#xff0c;并分享&#xff0c;和大家一起交流進步。 本文介紹如何在 Visual Studio Code (VSCode) 中安裝和自定義配置 CLine 插件&#xff0c;并使用 Claude 3.7 模…

    【VSCode配置】運行springboot項目和vue項目

    目錄 安裝VSCode安裝軟件安裝插件VSCode配置user的全局設置setting.jsonworkshop的項目自定義設置setting.jsonworkshop的項目啟動配置launch.json 安裝VSCode 官網下載 安裝軟件 git安裝1.1.12版本&#xff0c;1.2.X高版本無法安裝node14以下版本 nvm安裝&#xff08;github…

    linux shell編程之條件語句(二)

    目錄 一. 條件測試操作 1. 文件測試 2. 整數值比較 3. 字符串比較 4. 邏輯測試 二. if 條件語句 1. if 語句的結構 (1) 單分支 if 語句 (2) 雙分支 if 語句 (3) 多分支 if 語句 2. if 語句應用示例 (1) 單分支 if 語句應用 (2) 雙分支 if 語句應用 (3) 多分支 …

    榕壹云在線商城系統:基于THinkPHP+ Mysql+UniApp全端適配、高效部署的電商解決方案

    項目背景&#xff1a;解決多端電商開發的痛點 隨著移動互聯網的普及和用戶購物習慣的碎片化&#xff0c;傳統電商系統面臨以下挑戰&#xff1a; 1. 多平臺適配成本高&#xff1a;需要同時開發App、小程序、H5等多端應用&#xff0c;重復開發導致資源浪費。 2. 技術依賴第三方…

    神經動力學系統與計算及AI拓展

    大腦&#xff0c;一個蘊藏在我們顱骨之內的宇宙&#xff0c;以活動脈動&#xff0c;如同由電信號和化學信號編織而成的交響樂&#xff0c;精巧地協調著思想、情感和行為。但是&#xff0c;這種復雜的神經元舞蹈是如何產生我們豐富多彩的精神生活的呢&#xff1f;這正是神經動力…

    K8s常用基礎管理命令(一)

    基礎管理命令 基礎命令kubectl get命令kubectl create命令kubectl apply命令kubectl delete命令kubectl describe命令kubectl explain命令kubectl run命令kubectl cp命令kubectl edit命令kubectl logs命令kubectl exec命令kubectl port-forward命令kubectl patch命令 集群管理命…

    本地化部署DeepSeek-R1蒸餾大模型:基于飛槳PaddleNLP 3.0的實戰指南

    目錄 一、飛槳框架3.0&#xff1a;大模型推理新范式的開啟1.1 自動并行機制革新&#xff1a;解放多卡推理1.2 推理-訓練統一設計&#xff1a;一套代碼全流程復用 二、本地部署DeepSeek-R1-Distill-Llama-8B的實戰流程2.1 機器環境說明2.2 模型與推理腳本準備2.3 啟動 Docker 容…

    單片機方案開發 代寫程序/燒錄芯片 九齊/應廣等 電動玩具 小家電 語音開發

    在電子產品設計中&#xff0c;單片機&#xff08;MCU&#xff09;無疑是最重要的組成部分之一。無論是消費電子、智能家居、工業控制&#xff0c;還是可穿戴設備&#xff0c;小家電等&#xff0c;單片機的應用無處不在。 單片機&#xff0c;簡而言之&#xff0c;就是將計算機…