【Linux C/C++开发】第20章:进程间通信理论

第20章:进程间通信理论

20.1 进程间通信基础理论

20.1.1 进程与线程的区别:用餐厅来理解

想象一下你去餐厅吃饭:

进程(Process) - 就像一家完整的餐厅

  • 有独立的厨房(内存空间)、收银台(文件描述符)、员工(系统资源)
  • 每家餐厅都是独立的,不能直接使用隔壁餐厅的资源
  • 一个餐厅可以服务多个顾客(线程)

线程(Thread) - 就像餐厅里的服务员

  • 多个服务员共享同一家餐厅的厨房、收银台等资源
  • 每个服务员有自己的工作区域(栈空间)和工作记录(寄存器)
  • 服务员之间可以方便地共享餐厅的资源

资源隔离与共享

cpp 复制代码
/**
 * 进程资源隔离:每个进程就像独立的餐厅
 * 
 * 想象你有两家餐厅(进程):
 * 1. 麦当劳和肯德基不能共享厨房(内存空间)
 * 2. 每家店有自己的收银系统(文件描述符)
 * 3. 员工不能随意到隔壁店工作(进程ID不同)
 * 4. 每家店有自己的经营限制(系统资源限制)
 */

class ProcessIsolation {
private:
    pid_t pid_;                    // 进程ID(就像餐厅的营业执照号码)
    std::vector<void*> vmas_;      // 虚拟内存区域(餐厅的各个区域)
    std::vector<int> file_descriptors_; // 文件描述符(收银台编号)
    
public:
    /**
     * 创建独立的地址空间
     * 
     * 就像给新餐厅划分独立的区域:
     * - 厨房区域(代码段):只能厨师进入,存放制作流程
     * - 用餐区域(数据段):顾客可以修改,存放订单信息  
     * - 储物区域(栈段):临时存放物品,后进先出
     */
    bool create_isolated_address_space() {
        // 划分代码区域(厨房)- 只能读取和执行
        void* code_segment = mmap(nullptr, 4096, PROT_READ | PROT_EXEC, 
                                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        // 划分数据区域(用餐区)- 可以读写
        void* data_segment = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, 
                                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        // 划分栈区域(储物区)- 可以读写,向下增长
        void* stack_segment = mmap(nullptr, 8192, PROT_READ | PROT_WRITE, 
                                  MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
        
        // 检查区域划分是否成功
        if (code_segment == MAP_FAILED || data_segment == MAP_FAILED || 
            stack_segment == MAP_FAILED) {
            return false;  // 地盘划分失败
        }
        
        // 记录各个区域
        vmas_.push_back(code_segment);
        vmas_.push_back(data_segment);
        vmas_.push_back(stack_segment);
        
        return true;  // 餐厅区域划分成功
    }
    
    /**
     * 文件描述符隔离
     * 
     * 就像餐厅管理自己的设备:
     * - 关闭从原餐厅继承的不必要设备
     * - 只保留基本的:收银台(0)、菜单显示屏(1)、错误报警器(2)
     */
    bool create_isolated_file_descriptors() {
        // 关闭从父进程继承的文件描述符(除了标准设备)
        struct rlimit rlim;
        if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
            for (int fd = 3; fd < rlim.rlim_cur; ++fd) {
                close(fd);  // 关闭多余的设备
            }
        }
        
        // 只保留标准设备
        file_descriptors_ = {0, 1, 2}; // stdin(收银台), stdout(显示屏), stderr(报警器)
        return true;
    }
    
    /**
     * 获取进程资源使用情况
     * 
     * 就像查看餐厅的经营数据:
     * - 厨师工作时间:用户CPU时间
     * - 经理工作时间:系统CPU时间  
     * - 实际占用面积:常驻内存
     * - 总租用面积:虚拟内存
     */
    struct ResourceUsage {
        double cpu_user_time;      // 用户CPU时间(厨师工作时间)
        double cpu_system_time;    // 系统CPU时间(经理工作时间)
        size_t memory_rss;       // 常驻内存(实际使用面积)
        size_t memory_vsize;       // 虚拟内存(总租用面积)
        size_t io_read_bytes;    // 读取字节数
        size_t io_write_bytes;   // 写入字节数
        size_t num_file_descriptors; // 文件描述符数
    };
    
    ResourceUsage get_resource_usage() const {
        ResourceUsage usage = {};
        
        // 从/proc/[pid]/stat获取CPU和内存信息
        std::string stat_path = "/proc/" + std::to_string(pid_) + "/stat";
        std::ifstream stat_file(stat_path);
        
        if (stat_file.is_open()) {
            std::string line;
            std::getline(stat_file, line);
            
            // 解析stat文件(简化版本)
            std::istringstream iss(line);
            std::vector<std::string> tokens;
            std::string token;
            
            while (iss >> token) {
                tokens.push_back(token);
            }
            
            if (tokens.size() > 23) {
                // utime (14), stime (15)
                usage.cpu_user_time = std::stoull(tokens[13]) / sysconf(_SC_CLK_TCK);
                usage.cpu_system_time = std::stoull(tokens[14]) / sysconf(_SC_CLK_TCK);
                
                // rss (24) - 页数转换为KB
                usage.memory_rss = std::stoull(tokens[23]) * (sysconf(_SC_PAGESIZE) / 1024);
                
                // vsize (23)
                usage.memory_vsize = std::stoull(tokens[22]) / 1024;
            }
        }
        
        // 从/proc/[pid]/io获取I/O统计
        std::string io_path = "/proc/" + std::to_string(pid_) + "/io";
        std::ifstream io_file(io_path);
        
        if (io_file.is_open()) {
            std::string line;
            while (std::getline(io_file, line)) {
                if (line.find("read_bytes:") == 0) {
                    usage.io_read_bytes = std::stoull(line.substr(12));
                } else if (line.find("write_bytes:") == 0) {
                    usage.io_write_bytes = std::stoull(line.substr(13));
                }
            }
        }
        
        usage.num_file_descriptors = file_descriptors_.size();
        return usage;
    }
};

20.1.2 进程间通信机制分类:用快递系统来理解

通信模型分类

  1. 共享内存(Shared Memory):就像共享仓库

    • 多个进程可以同时访问同一块内存区域
    • 速度快,但需要协调访问(就像多人共用仓库需要排队)
  2. 消息传递(Message Passing):就像快递服务

    • 进程A把消息放入队列,进程B从队列取出
    • 不需要共享物理空间,通过中间人传递
  3. 管道(Pipe):就像水管

    • 数据像水一样单向流动
    • 一端写入,另一端读取
  4. 信号(Signal):就像门铃

    • 异步通知机制,有人按门铃你就知道有事情发生
    • 简单但信息量少
  5. 套接字(Socket):就像电话系统

    • 可以本地或网络通信
    • 双向通信,功能最强大

20.2 管道(Pipe)通信理论:用水管理解进程通信

20.2.1 匿名管道:父子进程间的"秘密水管"

想象父子进程之间建立了一条秘密水管:

核心概念

  • 单向流动:水只能从一个方向流(半双工通信)
  • 家庭专用:只有一家人能用(亲缘关系进程)
  • 蓄水池:内核提供了一个缓冲区(64KB的"蓄水池")
  • 等待机制:水池满了或空了都要等待(阻塞I/O)
cpp 复制代码
#include <unistd.h>
#include <sys/wait.h>
#include <iostream>
#include <string>

/**
 * 匿名管道:父子进程的秘密通信
 * 
 * 生活化理解:
 * 1. 爸爸在厨房做饭,孩子在客厅看电视
 * 2. 他们之间有一根水管:爸爸可以往里面放饮料,孩子可以取出来喝
 * 3. 水管是单向的:爸爸能给孩子送饮料,但孩子不能通过同根水管送东西给爸爸
 * 4. 这根水管只有家里人能用(亲缘关系)
 * 5. 有一个蓄水池缓冲,爸爸可以一次性放多瓶饮料进去
 */

class FamilyCommunicationPipe {
private:
    int read_fd_;   // 读端(孩子的取饮料口)
    int write_fd_;  // 写端(爸爸的放饮料口)
    bool is_parent_; // 当前是爸爸还是孩子
    
public:
    FamilyCommunicationPipe() : read_fd_(-1), write_fd_(-1), is_parent_(false) {
        int pipe_fds[2];  // 创建水管的两个端口
        
        // 创建匿名管道(安装家庭水管)
        if (pipe(pipe_fds) < 0) {
            throw std::runtime_error("Failed to create family communication pipe");
        }
        
        read_fd_ = pipe_fds[0];   // 0端:读端(孩子的取口)
        write_fd_ = pipe_fds[1];  // 1端:写端(爸爸的放口)
        
        std::cout << "家庭水管安装完成:爸爸端口=" << write_fd_ 
                  << ", 孩子端口=" << read_fd_ << std::endl;
    }
 * - 阻塞条件:写阻塞当可用空间 < n,读阻塞当数据量 < n
 * - 原子性:写操作 ≤ PIPE_BUF(4096 bytes)时保证原子性
 */
class AnonymousPipe {
private:
    int read_fd_;   // 读端文件描述符
    int write_fd_;  // 写端文件描述符
    bool is_parent_; // 是否为父进程
    
public:
    AnonymousPipe() : read_fd_(-1), write_fd_(-1), is_parent_(false) {
        int pipe_fds[2];
        
        // 创建匿名管道
        if (pipe(pipe_fds) < 0) {
            throw std::runtime_error("Failed to create pipe");
        }
        
        read_fd_ = pipe_fds[0];
        write_fd_ = pipe_fds[1];
        
        // 设置为非阻塞模式(可选)
        set_nonblocking(read_fd_);
        set_nonblocking(write_fd_);
    }
    
    ~FamilyCommunicationPipe() {
        close_pipe();
    }
    
    /**
     * 家庭成员角色分配
     * 
     * 就像家庭分工:
     * - 爸爸负责制作饮料(写端)
     * - 孩子负责享用饮料(读端)
     * - 每个人只能用自己的端口,不能混用
     */
    void assign_family_roles() {
        pid_t pid = fork();
        
        if (pid < 0) {
            throw std::runtime_error("Family creation failed");
        } else if (pid > 0) {
            // 爸爸进程
            is_parent_ = true;
            close(read_fd_);  // 爸爸不需要取饮料口
            read_fd_ = -1;
            std::cout << "爸爸角色分配完成,负责制作饮料" << std::endl;
        } else {
            // 孩子进程
            is_parent_ = false;
            close(write_fd_); // 孩子不需要制作饮料口
            write_fd_ = -1;
            std::cout << "孩子角色分配完成,负责享用饮料" << std::endl;
        }
    }
    
    /**
     * 爸爸制作饮料
     * 
     * 制作规则:
     * 1. 如果蓄水池满了,需要等待(阻塞模式)
     * 2. 一次制作少量饮料(≤4096字节)能保证不被打断
     * 3. 如果孩子离开(读端关闭),爸爸会收到通知(SIGPIPE)
     */
    bool make_beverage(const std::string& drink_name) {
        if (write_fd_ < 0) {
            std::cout << "错误:这不是爸爸角色,不能制作饮料" << std::endl;
            return false;
        }
        
        std::string beverage = drink_name + "\n";
        ssize_t result = write(write_fd_, beverage.c_str(), beverage.length());
        
        if (result < 0) {
            if (errno == EPIPE) {
                std::cout << "孩子已经离开,无法继续提供饮料" << std::endl;
            } else if (errno == EAGAIN) {
                std::cout << "蓄水池满了,请稍后再制作" << std::endl;
            } else {
                std::cout << "制作饮料失败:" << strerror(errno) << std::endl;
            }
            return false;
        }
        
        std::cout << "爸爸制作了:" << drink_name << "(" << result << "字节)" << std::endl;
        return true;
    }
    
    /**
     * 孩子享用饮料
     * 
     * 享用规则:
     * 1. 如果蓄水池空了且爸爸还在制作,需要等待
     * 2. 如果蓄水池空了且爸爸已经离开,知道没有更多饮料了(EOF)
     * 3. 一次可能收到多种饮料的混合
     */
    ssize_t read_from_pipe(void* buffer, size_t size) {
        if (read_fd_ < 0) {
            return -1; // 没有读端
        }
        
        ssize_t bytes_read = read(read_fd_, buffer, size);
        
        if (bytes_read < 0) {
            if (errno == EAGAIN) {
                // 非阻塞模式下,管道为空
                return 0;
            } else {
                perror("Read from pipe failed");
            }
        } else if (bytes_read == 0) {
            // 写端已关闭,到达EOF
            std::cout << "Pipe EOF - writer closed" << std::endl;
        }
        
        return bytes_read;
    }
    
    /**
     * 获取管道缓冲区状态
     * 
     * 通过FIONREAD ioctl获取管道中可读的字节数
     */
    int get_available_bytes() const {
        if (read_fd_ < 0) return 0;
        
        int available = 0;
        if (ioctl(read_fd_, FIONREAD, &available) < 0) {
            perror("FIONREAD failed");
            return -1;
        }
        
        return available;
    }
    
private:
    void set_nonblocking(int fd) {
        int flags = fcntl(fd, F_GETFL, 0);
        fcntl(fd, F_SETFL, flags | O_NONBLOCK);
    }
    
    void close_pipe() {
        if (read_fd_ >= 0) {
            close(read_fd_);
            read_fd_ = -1;
        }
        
        if (write_fd_ >= 0) {
            close(write_fd_);
            write_fd_ = -1;
        }
    }
};

/**
 * 双向管道通信
 * 
 * 实现父子进程间的双向通信,需要两个匿名管道
 * 管道1:父进程写,子进程读
 * 管道2:子进程写,父进程读
 */
class BidirectionalPipe {
private:
    AnonymousPipe pipe_to_child_;   // 父→子通信
    AnonymousPipe pipe_to_parent_;  // 子→父通信
    
public:
    BidirectionalPipe() {
        // 管道已在构造函数中创建
    }
    
    void fork_and_setup() {
        pid_t pid = fork();
        
        if (pid < 0) {
            throw std::runtime_error("Fork failed");
        } else if (pid > 0) {
            // 父进程:关闭不需要的管道端
            setup_parent_end();
        } else {
            // 子进程:关闭不需要的管道端
            setup_child_end();
        }
    }
    
    // 父进程向子进程发送数据
    bool parent_send(const std::string& message) {
        return pipe_to_child_.write_to_pipe(message.c_str(), message.size()) > 0;
    }
    
    // 父进程从子进程接收数据
    std::string parent_receive() {
        char buffer[1024];
        ssize_t bytes = pipe_to_parent_.read_from_pipe(buffer, sizeof(buffer) - 1);
        
        if (bytes > 0) {
            buffer[bytes] = '\0';
            return std::string(buffer);
        }
        
        return "";
    }
    
    // 子进程向父进程发送数据
    bool child_send(const std::string& message) {
        return pipe_to_parent_.write_to_pipe(message.c_str(), message.size()) > 0;
    }
    
    // 子进程从父进程接收数据
    std::string child_receive() {
        char buffer[1024];
        ssize_t bytes = pipe_to_child_.read_from_pipe(buffer, sizeof(buffer) - 1);
        
        if (bytes > 0) {
            buffer[bytes] = '\0';
            return std::string(buffer);
        }
        
        return "";
    }
    
private:
    void setup_parent_end() {
        // 父进程:保留pipe_to_child的写端和pipe_to_parent的读端
        // 关闭pipe_to_child的读端和pipe_to_parent的写端
        // 这些操作已在fork_and_separate中完成
    }
    
    void setup_child_end() {
        // 子进程:保留pipe_to_child的读端和pipe_to_parent的写端
        // 关闭pipe_to_child的写端和pipe_to_parent的读端
        // 这些操作已在fork_and_separate中完成
    }
};

20.2.2 命名管道(Named Pipe/FIFO)

命名管道可以在无亲缘关系的进程间进行通信。

cpp 复制代码
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

/**
 * 命名管道理论实现
 * 
 * 核心特性:
 * 1. 文件系统可见:存在于文件系统中的特殊文件
 * 2. 无亲缘限制:任何进程都可以访问
 * 3. 双向通信:可以创建两个FIFO实现双向通信
 * 4. 持久性:直到显式删除或系统重启
 * 
 * 数学模型:
 * - FIFO容量:同匿名管道,通常64KB
 * - 访问权限:遵循Unix文件权限模型 ugo+rwx
 * - 阻塞行为:与匿名管道相同
 */
class NamedPipe {
private:
    std::string fifo_path_;     // FIFO文件路径
    int read_fd_;              // 读端文件描述符
    int write_fd_;             // 写端文件描述符
    bool is_creator_;          // 是否为创建者
    
public:
    NamedPipe(const std::string& path) : fifo_path_(path), read_fd_(-1), write_fd_(-1), is_creator_(false) {
        // 创建命名管道
        if (mkfifo(fifo_path_.c_str(), 0666) < 0) {
            if (errno != EEXIST) {
                throw std::runtime_error("Failed to create FIFO");
            }
            // FIFO已存在,尝试打开
        } else {
            is_creator_ = true;
        }
    }
    
    ~NamedPipe() {
        close_fifo();
        
        // 只有创建者才删除FIFO文件
        if (is_creator_) {
            unlink(fifo_path_.c_str());
        }
    }
    
    /**
     * 打开FIFO进行读写
     * 
     * 打开模式:
     * - O_RDONLY:只读模式,阻塞直到有写者
     * - O_WRONLY:只写模式,阻塞直到有读者
     * - O_RDWR:读写模式,不阻塞
     * - O_NONBLOCK:非阻塞模式
     */
    bool open_fifo(int flags = O_RDWR) {
        // 以读写模式打开,避免阻塞
        int fd = open(fifo_path_.c_str(), flags);
        if (fd < 0) {
            perror("Failed to open FIFO");
            return false;
        }
        
        // 根据flags设置读写端
        if (flags & O_RDONLY) {
            read_fd_ = fd;
        } else if (flags & O_WRONLY) {
            write_fd_ = fd;
        } else { // O_RDWR
            read_fd_ = fd;
            write_fd_ = fd;
        }
        
        return true;
    }
    
    /**
     * 分离读写端
     * 
     * 为了支持双向通信,需要分离读写端
     */
    bool separate_read_write() {
        if (read_fd_ >= 0 && write_fd_ >= 0 && read_fd_ == write_fd_) {
            // 当前是同一个文件描述符,需要分离
            write_fd_ = open(fifo_path_.c_str(), O_WRONLY);
            if (write_fd_ < 0) {
                perror("Failed to open FIFO for writing");
                return false;
            }
        }
        return true;
    }
    
    /**
     * 写入数据到FIFO
     * 
     * 与匿名管道类似,但支持更灵活的打开模式
     */
    ssize_t write_to_fifo(const void* data, size_t size) {
        if (write_fd_ < 0) {
            std::cerr << "No write descriptor available" << std::endl;
            return -1;
        }
        
        ssize_t written = write(write_fd_, data, size);
        
        if (written < 0) {
            if (errno == EPIPE) {
                std::cerr << "FIFO broken - no readers" << std::endl;
            } else if (errno == EAGAIN) {
                std::cerr << "FIFO full - try again later" << std::endl;
            } else {
                perror("Write to FIFO failed");
            }
        }
        
        return written;
    }
    
    /**
     * 从FIFO读取数据
     */
    ssize_t read_from_fifo(void* buffer, size_t size) {
        if (read_fd_ < 0) {
            std::cerr << "No read descriptor available" << std::endl;
            return -1;
        }
        
        ssize_t bytes_read = read(read_fd_, buffer, size);
        
        if (bytes_read < 0) {
            if (errno == EAGAIN) {
                // 非阻塞模式下,FIFO为空
                return 0;
            } else {
                perror("Read from FIFO failed");
            }
        } else if (bytes_read == 0) {
            // 所有写者已关闭
            std::cout << "FIFO EOF - no writers" << std::endl;
        }
        
        return bytes_read;
    }
    
    /**
     * 获取FIFO状态信息
     */
    struct FifoStatus {
        bool exists;              // FIFO文件是否存在
        mode_t permissions;       // 文件权限
        size_t size;              // 文件大小(通常为0)
        time_t creation_time;     // 创建时间
        time_t modification_time; // 修改时间
        int readers_count;        // 当前读者数量
        int writers_count;        // 当前写者数量
    };
    
    FifoStatus get_status() const {
        FifoStatus status = {};
        
        struct stat st;
        if (stat(fifo_path_.c_str(), &st) == 0) {
            status.exists = true;
            status.permissions = st.st_mode;
            status.size = st.st_size;
            status.creation_time = st.st_ctime;
            status.modification_time = st.st_mtime;
            
            // 通过/proc文件系统获取读者和写者数量
            // 这需要更复杂的实现,这里简化处理
            status.readers_count = -1; // 未知
            status.writers_count = -1; // 未知
        } else {
            status.exists = false;
        }
        
        return status;
    }
    
private:
    void close_fifo() {
        if (read_fd_ >= 0 && read_fd_ != write_fd_) {
            close(read_fd_);
            read_fd_ = -1;
        }
        
        if (write_fd_ >= 0) {
            close(write_fd_);
            write_fd_ = -1;
        }
    }
};

/**
 * 双向命名管道通信
 * 
 * 使用两个命名管道实现双向通信
 */
class BidirectionalNamedPipe {
private:
    std::unique_ptr<NamedPipe> pipe_a_to_b_;  // A→B通信
    std::unique_ptr<NamedPipe> pipe_b_to_a_;  // B→A通信
    std::string fifo_prefix_;                 // FIFO文件前缀
    
public:
    BidirectionalNamedPipe(const std::string& prefix) : fifo_prefix_(prefix) {
        // 创建两个命名管道
        std::string fifo1 = fifo_prefix_ + "_a_to_b";
        std::string fifo2 = fifo_prefix_ + "_b_to_a";
        
        pipe_a_to_b_ = std::make_unique<NamedPipe>(fifo1);
        pipe_b_to_a_ = std::make_unique<NamedPipe>(fifo2);
    }
    
    /**
     * 进程A初始化:打开读写端
     */
    bool initialize_process_a() {
        // A进程:pipe_a_to_b的写端,pipe_b_to_a的读端
        if (!pipe_a_to_b_->open_fifo(O_WRONLY)) return false;
        if (!pipe_b_to_a_->open_fifo(O_RDONLY)) return false;
        
        return true;
    }
    
    /**
     * 进程B初始化:打开读写端
     */
    bool initialize_process_b() {
        // B进程:pipe_a_to_b的读端,pipe_b_to_a的写端
        if (!pipe_a_to_b_->open_fifo(O_RDONLY)) return false;
        if (!pipe_b_to_a_->open_fifo(O_WRONLY)) return false;
        
        return true;
    }
    
    // 进程A发送数据给进程B
    bool a_send_to_b(const std::string& message) {
        return pipe_a_to_b_->write_to_fifo(message.c_str(), message.size()) > 0;
    }
    
    // 进程A从进程B接收数据
    std::string a_receive_from_b() {
        char buffer[1024];
        ssize_t bytes = pipe_b_to_a_->read_from_fifo(buffer, sizeof(buffer) - 1);
        
        if (bytes > 0) {
            buffer[bytes] = '\0';
            return std::string(buffer);
        }
        
        return "";
    }
    
    // 进程B发送数据给进程A
    bool b_send_to_a(const std::string& message) {
        return pipe_b_to_a_->write_to_fifo(message.c_str(), message.size()) > 0;
    }
    
    // 进程B从进程A接收数据
    std::string b_receive_from_a() {
        char buffer[1024];
        ssize_t bytes = pipe_a_to_b_->read_from_fifo(buffer, sizeof(buffer) - 1);
        
        if (bytes > 0) {
            buffer[bytes] = '\0';
            return std::string(buffer);
        }
        
        return "";
    }
};

20.3 System V IPC机制

20.3.1 消息队列

System V消息队列提供了更复杂的进程间通信机制。

cpp 复制代码
#include <sys/msg.h>
#include <sys/ipc.h>
#include <cstring>

/**
 * System V消息队列理论实现
 * 
 * 核心特性:
 * 1. 消息类型:支持不同类型的消息
 * 2. 优先级:可以按类型优先级接收
 * 3. 持久性:直到显式删除或系统重启
 * 4. 内核管理:由内核维护消息队列
 * 
 * 数学模型:
 * - 队列容量:msg_qbytes(通常受系统限制)
 * - 消息大小:0 < msg_sz ≤ MSGMAX(通常为8192字节)
 * - 消息数量:0 ≤ msg_qnum ≤ MSGMNB(通常为16384)
 */

// 消息结构体
struct Message {
    long mtype;     // 消息类型(必须 > 0)
    char mtext[1024]; // 消息内容
    
    Message() : mtype(1) {
        memset(mtext, 0, sizeof(mtext));
    }
    
    Message(long type, const std::string& text) : mtype(type) {
        strncpy(mtext, text.c_str(), sizeof(mtext) - 1);
        mtext[sizeof(mtext) - 1] = '\0';
    }
};

class SystemVMessageQueue {
private:
    int msgid_;                 // 消息队列ID
    key_t key_;                 // 消息队列键
    bool is_creator_;           // 是否为创建者
    
public:
    SystemVMessageQueue(key_t key = IPC_PRIVATE) : msgid_(-1), key_(key), is_creator_(false) {
        // 创建消息队列
        create_queue();
    }
    
    ~SystemVMessageQueue() {
        cleanup();
    }
    
    /**
     * 创建消息队列
     * 
     * 权限模型:
     * - IPC_CREAT:如果不存在则创建
     * - IPC_EXCL:与IPC_CREAT一起使用,如果存在则失败
     * - 权限位:0666(所有用户可读写)
     */
    bool create_queue() {
        if (key_ == IPC_PRIVATE) {
            // 私有队列,每次创建新的
            msgid_ = msgget(key_, IPC_CREAT | 0666);
            is_creator_ = true;
        } else {
            // 尝试获取已存在的队列,如果不存在则创建
            msgid_ = msgget(key_, IPC_CREAT | IPC_EXCL | 0666);
            if (msgid_ < 0 && errno == EEXIST) {
                // 队列已存在,尝试打开
                msgid_ = msgget(key_, 0666);
            } else if (msgid_ >= 0) {
                is_creator_ = true;
            }
        }
        
        if (msgid_ < 0) {
            perror("msgget failed");
            return false;
        }
        
        return true;
    }
    
    /**
     * 发送消息
     * 
     * 发送规则:
     * 1. 如果队列满,阻塞直到有空间(阻塞模式)
     * 2. 消息大小不能超过系统限制
     * 3. 消息类型必须 > 0
     * 
     * 数学模型:
     - 发送延迟:T_send = T_kernel + T_copy + T_sync
     * - 吞吐量:Throughput = msg_sz / T_send
     */
    bool send_message(long msg_type, const std::string& text, bool blocking = true) {
        if (msgid_ < 0) return false;
        
        Message msg(msg_type, text);
        size_t msg_size = sizeof(msg.mtext);
        
        int flags = 0;
        if (!blocking) {
            flags |= IPC_NOWAIT; // 非阻塞模式
        }
        
        if (msgsnd(msgid_, &msg, msg_size, flags) < 0) {
            if (errno == EAGAIN) {
                std::cerr << "Message queue full" << std::endl;
            } else if (errno == EINVAL) {
                std::cerr << "Invalid message size or type" << std::endl;
            } else {
                perror("msgsnd failed");
            }
            return false;
        }
        
        return true;
    }
    
    /**
     * 接收消息
     * 
     * 接收模式:
     * 1. msgtyp > 0:接收指定类型的第一个消息
     * 2. msgtyp = 0:接收队列中的第一个消息
     * 3. msgtyp < 0:接收类型 ≤ |msgtyp| 的最小类型消息
     * 
     * 性能特征:
     * - 时间复杂度:O(n) 最坏情况,需要遍历消息队列
     * - 空间复杂度:O(1),使用用户提供的缓冲区
     */
    std::string receive_message(long msg_type = 0, bool blocking = true) {
        if (msgid_ < 0) return "";
        
        Message msg;
        size_t msg_size = sizeof(msg.mtext);
        
        int flags = 0;
        if (!blocking) {
            flags |= IPC_NOWAIT; // 非阻塞模式
        }
        
        ssize_t bytes_received = msgrcv(msgid_, &msg, msg_size, msg_type, flags);
        
        if (bytes_received < 0) {
            if (errno == ENOMSG) {
                // 没有指定类型的消息(非阻塞模式)
                return "";
            } else if (errno == EAGAIN) {
                // 队列为空(非阻塞模式)
                return "";
            } else if (errno == E2BIG) {
                std::cerr << "Message too large for buffer" << std::endl;
                return "";
            } else {
                perror("msgrcv failed");
                return "";
            }
        }
        
        return std::string(msg.mtext, bytes_received);
    }
    
    /**
     * 获取队列状态信息
     * 
     * 通过msgctl获取队列的统计信息
     */
    struct QueueInfo {
        long msg_qnum;     // 当前消息数量
        long msg_qbytes;   // 队列最大字节数
        long msg_lspid;    // 最后发送进程PID
        long msg_lrpid;    // 最后接收进程PID
        time_t msg_stime;  // 最后发送时间
        time_t msg_rtime;  // 最后接收时间
        time_t msg_ctime;  // 最后修改时间
        uid_t msg_perm.uid; // 所有者UID
        gid_t msg_perm.gid; // 所有者GID
        mode_t msg_perm.mode; // 权限模式
    };
    
    QueueInfo get_queue_info() const {
        QueueInfo info = {};
        
        if (msgid_ < 0) return info;
        
        struct msqid_ds queue_info;
        if (msgctl(msgid_, IPC_STAT, &queue_info) < 0) {
            perror("msgctl IPC_STAT failed");
            return info;
        }
        
        info.msg_qnum = queue_info.msg_qnum;
        info.msg_qbytes = queue_info.msg_qbytes;
        info.msg_lspid = queue_info.msg_lspid;
        info.msg_lrpid = queue_info.msg_lrpid;
        info.msg_stime = queue_info.msg_stime;
        info.msg_rtime = queue_info.msg_rtime;
        info.msg_ctime = queue_info.msg_ctime;
        info.msg_perm.uid = queue_info.msg_perm.uid;
        info.msg_perm.gid = queue_info.msg_perm.gid;
        info.msg_perm.mode = queue_info.msg_perm.mode;
        
        return info;
    }
    
    /**
     * 修改队列属性
     * 
     * 可以修改队列的权限和最大字节数
     */
    bool set_queue_properties(mode_t permissions, size_t max_bytes) {
        if (msgid_ < 0) return false;
        
        struct msqid_ds queue_info;
        
        // 获取当前队列信息
        if (msgctl(msgid_, IPC_STAT, &queue_info) < 0) {
            perror("msgctl IPC_STAT failed");
            return false;
        }
        
        // 修改属性
        queue_info.msg_perm.mode = permissions;
        queue_info.msg_qbytes = max_bytes;
        
        // 设置新属性
        if (msgctl(msgid_, IPC_SET, &queue_info) < 0) {
            perror("msgctl IPC_SET failed");
            return false;
        }
        
        return true;
    }
    
    /**
     * 清空消息队列
     * 
     * 通过读取所有消息来清空队列
     */
    void clear_queue() {
        QueueInfo info = get_queue_info();
        
        // 读取所有消息
        for (long i = 0; i < info.msg_qnum; ++i) {
            receive_message(0, false); // 非阻塞接收
        }
    }
    
private:
    void cleanup() {
        if (msgid_ >= 0 && is_creator_) {
            // 删除消息队列
            if (msgctl(msgid_, IPC_RMID, nullptr) < 0) {
                perror("msgctl IPC_RMID failed");
            }
        }
    }
};

/**
 * 高级消息队列管理器
 * 
 * 支持多进程间的复杂通信模式
 */
class AdvancedMessageQueue {
private:
    std::unique_ptr<SystemVMessageQueue> request_queue_;   // 请求队列
    std::unique_ptr<SystemVMessageQueue> response_queue_;  // 响应队列
    
public:
    AdvancedMessageQueue(key_t request_key, key_t response_key) {
        request_queue_ = std::make_unique<SystemVMessageQueue>(request_key);
        response_queue_ = std::make_unique<SystemVMessageQueue>(response_key);
    }
    
    /**
     * 客户端-服务器通信模式
     * 
     * 通信流程:
     * 1. 客户端发送请求到请求队列
     * 2. 服务器从请求队列接收请求
     * 3. 服务器处理请求并发送响应到响应队列
     * 4. 客户端从响应队列接收响应
     * 
     * 数学模型:
     * - 请求延迟:T_req = T_send + T_queue + T_process + T_response
     * - 吞吐量:Throughput = 1 / T_req
     * - 并发度:取决于服务器处理能力
     */
    
    // 客户端发送请求
    bool client_send_request(const std::string& request, long client_id) {
        return request_queue_->send_message(client_id, request);
    }
    
    // 客户端接收响应
    std::string client_receive_response(long client_id) {
        return response_queue_->receive_message(client_id);
    }
    
    // 服务器接收请求
    std::pair<std::string, long> server_receive_request() {
        // 接收任意类型的消息(阻塞)
        std::string request = request_queue_->receive_message(0, true);
        
        if (!request.empty()) {
            // 获取发送者的客户端ID(通过消息类型)
            auto info = request_queue_->get_queue_info();
            long client_id = info.msg_lrpid; // 最后接收的进程ID
            
            return {request, client_id};
        }
        
        return {"", -1};
    }
    
    // 服务器发送响应
    bool server_send_response(const std::string& response, long client_id) {
        return response_queue_->send_message(client_id, response);
    }
};

20.3.2 共享内存

共享内存是最快的IPC机制,允许多个进程共享同一块物理内存。

cpp 复制代码
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/mman.h>

/**
 * System V共享内存理论实现
 * 
 * 核心特性:
 * 1. 零拷贝:无需内核空间复制
 * 2. 高性能:直接内存访问
 * 3. 同步需求:需要额外的同步机制
 * 4. 持久性:直到显式删除或系统重启
 * 
 * 数学模型:
 * - 访问延迟:T_access = T_mmu + T_cache + T_memory
 * - 带宽:Bandwidth = min(Memory_bandwidth, Cache_bandwidth)
 * - 并发控制:需要信号量或互斥锁
 */

class SystemVSharedMemory {
private:
    int shmid_;                 // 共享内存ID
    key_t key_;                 // 共享内存键
    void* shm_addr_;            // 共享内存地址
    size_t size_;               // 共享内存大小
    bool is_creator_;           // 是否为创建者
    
public:
    SystemVSharedMemory(key_t key, size_t size) 
        : shmid_(-1), key_(key), shm_addr_(nullptr), size_(size), is_creator_(false) {
        create_shared_memory();
    }
    
    ~SystemVSharedMemory() {
        cleanup();
    }
    
    /**
     * 创建共享内存
     * 
     * 创建标志:
     * - IPC_CREAT:创建新的共享内存
     * - IPC_EXCL:与IPC_CREAT一起使用,如果存在则失败
     * - SHM_R:读权限
     * - SHM_W:写权限
     * 
     * 数学分析:
     * - 内存分配:按页对齐,size = ceil(size / PAGE_SIZE) * PAGE_SIZE
     * - 权限检查:mode & ~umask
     */
    bool create_shared_memory() {
        int flags = IPC_CREAT | 0666; // 读写权限
        
        if (key_ != IPC_PRIVATE) {
            flags |= IPC_EXCL; // 尝试创建新的
        }
        
        shmid_ = shmget(key_, size_, flags);
        
        if (shmid_ < 0) {
            if (errno == EEXIST && (flags & IPC_EXCL)) {
                // 已存在,尝试打开
                shmid_ = shmget(key_, 0, 0666);
                if (shmid_ >= 0) {
                    // 获取实际大小
                    struct shmid_ds shm_info;
                    if (shmctl(shmid_, IPC_STAT, &shm_info) == 0) {
                        size_ = shm_info.shm_segsz;
                    }
                }
            }
            
            if (shmid_ < 0) {
                perror("shmget failed");
                return false;
            }
        } else {
            is_creator_ = true;
        }
        
        // 附加共享内存到进程地址空间
        attach_shared_memory();
        
        return true;
    }
    
    /**
     * 附加共享内存
     * 
     * 附加标志:
     * - SHM_RDONLY:只读附加
     * - SHM_RND:地址向下对齐到SHMLBA
     * - 0:读写附加
     * 
     * 地址映射:
     * - 内核选择地址:shm_addr = nullptr
     * - 用户指定地址:shm_addr = user_address
     */
    bool attach_shared_memory(void* attach_addr = nullptr, bool read_only = false) {
        if (shmid_ < 0) return false;
        
        int flags = 0;
        if (read_only) {
            flags |= SHM_RDONLY;
        }
        
        shm_addr_ = shmat(shmid_, attach_addr, flags);
        
        if (shm_addr_ == reinterpret_cast<void*>(-1)) {
            perror("shmat failed");
            shm_addr_ = nullptr;
            return false;
        }
        
        return true;
    }
    
    /**
     * 分离共享内存
     * 
     * 分离过程:
     * 1. 减少引用计数
     * 2. 从进程地址空间移除映射
     * 3. 如果引用计数为0,标记为销毁(如果已标记IPC_RMID)
     */
    bool detach_shared_memory() {
        if (shm_addr_ == nullptr) return true;
        
        if (shmdt(shm_addr_) < 0) {
            perror("shmdt failed");
            return false;
        }
        
        shm_addr_ = nullptr;
        return true;
    }
    
    /**
     * 写入数据到共享内存
     * 
     * 内存访问:
     * - 直接内存访问,无系统调用开销
     * - 需要同步机制保护并发访问
     * - 遵循CPU内存模型(缓存一致性)
     * 
     * 性能分析:
     * - 延迟:T_write = T_cache + T_memory(约50-100ns)
     * - 带宽:受限于内存带宽(约20-50 GB/s)
     */
    bool write_data(size_t offset, const void* data, size_t size) {
        if (shm_addr_ == nullptr || offset + size > size_) {
            return false;
        }
        
        // 边界检查
        if (data == nullptr || size == 0) {
            return false;
        }
        
        // 直接内存复制
        memcpy(static_cast<char*>(shm_addr_) + offset, data, size);
        
        // 内存屏障:确保写入完成
        __sync_synchronize();
        
        return true;
    }
    
    /**
     * 从共享内存读取数据
     * 
     * 读取过程:
     * 1. 检查边界条件
     * 2. 直接内存复制
     * 3. 可选的内存屏障
     */
    bool read_data(size_t offset, void* buffer, size_t size) const {
        if (shm_addr_ == nullptr || offset + size > size_ || buffer == nullptr) {
            return false;
        }
        
        // 内存屏障:确保读取最新数据
        __sync_synchronize();
        
        // 直接内存复制
        memcpy(buffer, static_cast<const char*>(shm_addr_) + offset, size);
        
        return true;
    }
    
    /**
     * 获取共享内存信息
     * 
     * 统计信息:
     * - 段大小:shmid_ds.shm_segsz
     * - 附加进程数:shmid_ds.shm_nattch
     * - 最后操作时间:shmid_ds.shm_atime, shm_dtime, shm_ctime
     * - 创建者信息:shmid_ds.shm_perm.uid, gid
     */
    struct SharedMemoryInfo {
        size_t size;               // 段大小
        int attach_count;          // 附加进程数
        time_t last_attach_time;   // 最后附加时间
        time_t last_detach_time;   // 最后分离时间
        time_t last_change_time;   // 最后修改时间
        uid_t creator_uid;         // 创建者UID
        gid_t creator_gid;         // 创建者GID
        uid_t owner_uid;           // 所有者UID
        gid_t owner_gid;           // 所有者GID
        mode_t permissions;        // 权限模式
    };
    
    SharedMemoryInfo get_info() const {
        SharedMemoryInfo info = {};
        
        if (shmid_ < 0) return info;
        
        struct shmid_ds shm_info;
        if (shmctl(shmid_, IPC_STAT, &shm_info) < 0) {
            perror("shmctl IPC_STAT failed");
            return info;
        }
        
        info.size = shm_info.shm_segsz;
        info.attach_count = shm_info.shm_nattch;
        info.last_attach_time = shm_info.shm_atime;
        info.last_detach_time = shm_info.shm_dtime;
        info.last_change_time = shm_info.shm_ctime;
        info.creator_uid = shm_info.shm_perm.cuid;
        info.creator_gid = shm_info.shm_perm.cgid;
        info.owner_uid = shm_info.shm_perm.uid;
        info.owner_gid = shm_info.shm_perm.gid;
        info.permissions = shm_info.shm_perm.mode;
        
        return info;
    }
    
    /**
     * 修改共享内存属性
     * 
     * 可修改属性:
     * - 所有者UID/GID
     * - 权限模式
     * - 段大小(某些系统支持)
     */
    bool set_properties(uid_t uid, gid_t gid, mode_t mode) {
        if (shmid_ < 0) return false;
        
        struct shmid_ds shm_info;
        
        // 获取当前信息
        if (shmctl(shmid_, IPC_STAT, &shm_info) < 0) {
            perror("shmctl IPC_STAT failed");
            return false;
        }
        
        // 修改属性
        shm_info.shm_perm.uid = uid;
        shm_info.shm_perm.gid = gid;
        shm_info.shm_perm.mode = mode;
        
        // 设置新属性
        if (shmctl(shmid_, IPC_SET, &shm_info) < 0) {
            perror("shmctl IPC_SET failed");
            return false;
        }
        
        return true;
    }
    
    /**
     * 获取共享内存地址
     */
    void* get_address() const {
        return shm_addr_;
    }
    
    /**
     * 获取共享内存大小
     */
    size_t get_size() const {
        return size_;
    }
    
private:
    void cleanup() {
        detach_shared_memory();
        
        if (shmid_ >= 0 && is_creator_) {
            // 标记为销毁(当所有进程都分离时)
            if (shmctl(shmid_, IPC_RMID, nullptr) < 0) {
                perror("shmctl IPC_RMID failed");
            }
        }
    }
};

/**
 * POSIX共享内存实现
 * 
 * 相比System V共享内存,POSIX共享内存更现代,使用更简单
 */
class PosixSharedMemory {
private:
    std::string name_;              // 共享内存名称
    int fd_;                       // 文件描述符
    void* addr_;                   // 映射地址
    size_t size_;                  // 大小
    bool is_creator_;               // 是否为创建者
    
public:
    PosixSharedMemory(const std::string& name, size_t size) 
        : name_(name), fd_(-1), addr_(nullptr), size_(size), is_creator_(false) {
        create_shared_memory();
    }
    
    ~PosixSharedMemory() {
        cleanup();
    }
    
    /**
     * 创建POSIX共享内存
     * 
     * 创建标志:
     * - O_CREAT:如果不存在则创建
     * - O_EXCL:与O_CREAT一起使用,如果存在则失败
     * - O_RDWR:读写模式
     * - O_RDONLY:只读模式
     * 
     * 权限模式:
     * - S_IRUSR:用户读权限
     * - S_IWUSR:用户写权限
     * - S_IRGRP:组读权限
     * - S_IWGRP:组写权限
     * - S_IROTH:其他用户读权限
     * - S_IWOTH:其他用户写权限
     */
    bool create_shared_memory() {
        // 创建共享内存对象
        fd_ = shm_open(name_.c_str(), O_CREAT | O_EXCL | O_RDWR, 0666);
        
        if (fd_ < 0) {
            if (errno == EEXIST) {
                // 已存在,尝试打开
                fd_ = shm_open(name_.c_str(), O_RDWR, 0666);
                if (fd_ >= 0) {
                    // 获取大小
                    struct stat st;
                    if (fstat(fd_, &st) == 0) {
                        size_ = st.st_size;
                    }
                }
            }
        } else {
            is_creator_ = true;
            
            // 设置大小
            if (ftruncate(fd_, size_) < 0) {
                perror("ftruncate failed");
                close(fd_);
                fd_ = -1;
                return false;
            }
        }
        
        if (fd_ < 0) {
            perror("shm_open failed");
            return false;
        }
        
        // 映射到进程地址空间
        return map_shared_memory();
    }
    
    /**
     * 映射共享内存
     * 
     * 映射标志:
     * - PROT_READ:读权限
     * - PROT_WRITE:写权限
     * - MAP_SHARED:共享映射
     * - MAP_PRIVATE:私有映射(写时复制)
     */
    bool map_shared_memory(void* addr = nullptr, bool read_only = false) {
        if (fd_ < 0) return false;
        
        int prot = PROT_READ;
        if (!read_only) {
            prot |= PROT_WRITE;
        }
        
        addr_ = mmap(addr, size_, prot, MAP_SHARED, fd_, 0);
        
        if (addr_ == MAP_FAILED) {
            perror("mmap failed");
            addr_ = nullptr;
            return false;
        }
        
        return true;
    }
    
    /**
     * 取消映射
     */
    bool unmap_shared_memory() {
        if (addr_ == nullptr) return true;
        
        if (munmap(addr_, size_) < 0) {
            perror("munmap failed");
            return false;
        }
        
        addr_ = nullptr;
        return true;
    }
    
    /**
     * 数据访问方法(与System V共享内存类似)
     */
    bool write_data(size_t offset, const void* data, size_t size) {
        if (addr_ == nullptr || offset + size > size_ || data == nullptr) {
            return false;
        }
        
        memcpy(static_cast<char*>(addr_) + offset, data, size);
        __sync_synchronize(); // 内存屏障
        
        return true;
    }
    
    bool read_data(size_t offset, void* buffer, size_t size) const {
        if (addr_ == nullptr || offset + size > size_ || buffer == nullptr) {
            return false;
        }
        
        __sync_synchronize(); // 内存屏障
        memcpy(buffer, static_cast<const char*>(addr_) + offset, size);
        
        return true;
    }
    
    /**
     * 获取共享内存信息
     */
    struct SharedMemoryInfo {
        size_t size;           // 大小
        std::string name;      // 名称
        bool is_mapped;        // 是否已映射
        int fd;               // 文件描述符
    };
    
    SharedMemoryInfo get_info() const {
        SharedMemoryInfo info;
        info.size = size_;
        info.name = name_;
        info.is_mapped = (addr_ != nullptr);
        info.fd = fd_;
        return info;
    }
    
private:
    void cleanup() {
        unmap_shared_memory();
        
        if (fd_ >= 0) {
            close(fd_);
            fd_ = -1;
        }
        
        if (is_creator_) {
            shm_unlink(name_.c_str());
        }
    }
};

20.4 信号(Signal)通信

20.4.1 信号处理理论

信号是Unix系统中最古老的IPC机制,用于进程间的异步通知。

cpp 复制代码
#include <signal.h>
#include <cstring>

/**
 * 信号处理理论实现
 * 
 * 核心特性:
 * 1. 异步通知:信号可以在任何时候到达
 * 2. 有限类型:标准信号只有31种(SIGRTMIN之前)
 * 3. 不可靠性:标准信号可能丢失
 * 4. 可阻塞性:进程可以阻塞特定信号
 * 
 * 数学模型:
 * - 信号集合:S = {SIGINT, SIGTERM, SIGUSR1, ..., SIGRTMAX}
 * - 信号处理:Handler: S → Action,其中Action = {忽略, 默认, 捕获}
 * - 信号掩码:Mask ⊆ S,表示当前被阻塞的信号集合
 */

class SignalHandler {
private:
    static SignalHandler* instance_; // 单例实例
    sigset_t blocked_signals_;       // 被阻塞的信号集合
    std::unordered_map<int, std::function<void(int)>> handlers_; // 自定义处理器
    
public:
    SignalHandler() {
        // 初始化信号集合
        sigemptyset(&blocked_signals_);
        instance_ = this;
    }
    
    ~SignalHandler() {
        instance_ = nullptr;
    }
    
    /**
     * 注册信号处理器
     * 
     * 处理模式:
     * 1. SIG_DFL:默认处理
     * 2. SIG_IGN:忽略信号
     * 3. 自定义函数:用户定义的处理函数
     * 
     * 线程安全:信号处理函数必须是可重入的
     */
    bool register_handler(int signum, std::function<void(int)> handler) {
        if (signum < 1 || signum >= NSIG) {
            return false; // 无效信号编号
        }
        
        // 保存自定义处理器
        handlers_[signum] = handler;
        
        // 设置信号处理器
        struct sigaction sa;
        memset(&sa, 0, sizeof(sa));
        sa.sa_handler = signal_dispatcher;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = SA_RESTART; // 自动重启被中断的系统调用
        
        if (sigaction(signum, &sa, nullptr) < 0) {
            perror("sigaction failed");
            handlers_.erase(signum);
            return false;
        }
        
        return true;
    }
    
    /**
     * 阻塞信号
     * 
     * 阻塞机制:
     * 1. 信号被挂起,直到解除阻塞
     * 2. 被阻塞的信号不会触发处理器
     * 3. 可以阻塞多个信号
     * 
     * 数学模型:
     * - 阻塞集合:Blocked = {s | s ∈ S ∧ sigismember(&blocked_signals_, s)}
     * - 待处理信号:Pending = {s | s ∈ S ∧ sigpending(&pending_signals_)} 
     * - 有效信号:Effective = S - Blocked
     */
    bool block_signal(int signum) {
        if (signum < 1 || signum >= NSIG) {
            return false;
        }
        
        sigaddset(&blocked_signals_, signum);
        
        if (sigprocmask(SIG_BLOCK, &blocked_signals_, nullptr) < 0) {
            perror("sigprocmask SIG_BLOCK failed");
            sigdelset(&blocked_signals_, signum);
            return false;
        }
        
        return true;
    }
    
    /**
     * 解除信号阻塞
     */
    bool unblock_signal(int signum) {
        if (signum < 1 || signum >= NSIG) {
            return false;
        }
        
        sigdelset(&blocked_signals_, signum);
        
        if (sigprocmask(SIG_UNBLOCK, &blocked_signals_, nullptr) < 0) {
            perror("sigprocmask SIG_UNBLOCK failed");
            return false;
        }
        
        return true;
    }
    
    /**
     * 发送信号给进程
     * 
     * 发送规则:
     * 1. kill():发送信号给指定进程
     * 2. raise():发送信号给当前进程
     * 3. sigqueue():发送信号并附带数据
     * 
     * 权限检查:
     * - 超级用户可以发送信号给任何进程
     * - 普通用户只能发送信号给自己的进程
     * - 需要具有CAP_KILL能力
     */
    static bool send_signal(pid_t pid, int signum, int value = 0) {
        if (signum < 0 || signum >= NSIG) {
            return false;
        }
        
        union sigval sig_value;
        sig_value.sival_int = value;
        
        // 使用sigqueue发送信号和附带数据
        if (sigqueue(pid, signum, sig_value) < 0) {
            if (errno == EPERM) {
                std::cerr << "Permission denied to send signal" << std::endl;
            } else if (errno == ESRCH) {
                std::cerr << "Target process not found" << std::endl;
            } else {
                perror("sigqueue failed");
            }
            return false;
        }
        
        return true;
    }
    
    /**
     * 等待信号
     * 
     * 等待机制:
     * 1. pause():等待任意信号
     * 2. sigsuspend():临时替换信号掩码并等待
     * 3. sigtimedwait():带超时的信号等待
     * 
     * 返回值:
     * - 成功:返回信号编号
     * - 超时:返回-1,errno = EAGAIN
     * - 中断:返回-1,errno = EINTR
     */
    int wait_for_signal(const sigset_t* wait_set = nullptr, int timeout_ms = -1) {
        sigset_t effective_set;
        
        if (wait_set != nullptr) {
            effective_set = *wait_set;
        } else {
            // 等待所有信号
            sigfillset(&effective_set);
        }
        
        if (timeout_ms < 0) {
            // 无限等待
            int signum;
            sigwait(&effective_set, &signum);
            return signum;
        } else {
            // 带超时等待
            timespec timeout;
            timeout.tv_sec = timeout_ms / 1000;
            timeout.tv_nsec = (timeout_ms % 1000) * 1000000;
            
            siginfo_t siginfo;
            int signum = sigtimedwait(&effective_set, &siginfo, &timeout);
            
            if (signum < 0) {
                if (errno == EAGAIN) {
                    // 超时
                    return -1;
                } else if (errno == EINTR) {
                    // 被信号中断
                    return -2;
                } else {
                    perror("sigtimedwait failed");
                    return -3;
                }
            }
            
            return signum;
        }
    }
    
    /**
     * 获取待处理信号
     * 
     * 检查当前进程是否有待处理的信号
     */
    std::vector<int> get_pending_signals() const {
        std::vector<int> pending;
        sigset_t pending_signals;
        
        if (sigpending(&pending_signals) < 0) {
            perror("sigpending failed");
            return pending;
        }
        
        // 检查每个信号
        for (int signum = 1; signum < NSIG; ++signum) {
            if (sigismember(&pending_signals, signum)) {
                pending.push_back(signum);
            }
        }
        
        return pending;
    }
    
private:
    /**
     * 信号分发器
     * 
     * 静态函数,作为C信号处理器的包装器
     * 调用对应的C++成员函数
     */
    static void signal_dispatcher(int signum) {
        if (instance_ != nullptr) {
            auto it = instance_->handlers_.find(signum);
            if (it != instance_->handlers_.end() && it->second) {
                it->second(signum);
            }
        }
    }
    
    static SignalHandler* instance_;
};

// 静态成员定义
SignalHandler* SignalHandler::instance_ = nullptr;

/**
 * 高级信号通信系统
 * 
 * 实现进程间基于信号的复杂通信协议
 */
class AdvancedSignalCommunication {
private:
    std::unique_ptr<SignalHandler> handler_;
    pid_t peer_pid_;                    // 对等进程PID
    std::atomic<bool> communication_active_;
    
    // 信号协议定义
    enum SignalProtocol {
        SIG_HANDSHAKE = SIGUSR1,    // 握手信号
        SIG_DATA_READY = SIGUSR2,   // 数据就绪
        SIG_ACK = SIGRTMIN,         // 确认信号
        SIG_NACK = SIGRTMIN + 1,    // 否定确认
        SIG_HEARTBEAT = SIGRTMIN + 2 // 心跳信号
    };
    
public:
    AdvancedSignalCommunication(pid_t peer_pid) 
        : handler_(std::make_unique<SignalHandler>()), 
          peer_pid_(peer_pid), 
          communication_active_(false) {
        setup_protocol_handlers();
    }
    
    /**
     * 建立通信连接
     * 
     * 握手协议:
     * 1. 发送握手信号
     * 2. 等待对方握手信号
     * 3. 确认连接建立
     * 
     * 数学模型:
     * - 握手时间:T_handshake = 2 × T_signal + T_process
     * - 成功率:P_success = (1 - P_loss)^2,其中P_loss为信号丢失概率
     */
    bool establish_connection(int timeout_ms = 5000) {
        // 注册握手处理器
        std::promise<bool> handshake_promise;
        auto handshake_future = handshake_promise.get_future();
        
        handler_->register_handler(SIG_HANDSHAKE, 
            [&handshake_promise](int sig) {
                handshake_promise.set_value(true);
            });
        
        // 发送握手信号
        if (!SignalHandler::send_signal(peer_pid_, SIG_HANDSHAKE)) {
            return false;
        }
        
        // 等待对方握手信号
        if (handshake_future.wait_for(std::chrono::milliseconds(timeout_ms)) == 
            std::future_status::timeout) {
            return false;
        }
        
        communication_active_ = true;
        return true;
    }
    
    /**
     * 发送数据通知
     * 
     * 通知机制:
     * 1. 发送数据就绪信号
     * 2. 等待确认信号
     * 3. 处理超时和重传
     */
    bool notify_data_ready(int timeout_ms = 1000) {
        if (!communication_active_) return false;
        
        // 发送数据就绪信号
        return SignalHandler::send_signal(peer_pid_, SIG_DATA_READY);
    }
    
    /**
     * 发送心跳信号
     * 
     * 心跳机制:
     * 1. 定期发送心跳信号
     * 2. 检测连接状态
     * 3. 处理连接中断
     */
    bool send_heartbeat() {
        if (!communication_active_) return false;
        
        return SignalHandler::send_signal(peer_pid_, SIG_HEARTBEAT);
    }
    
private:
    void setup_protocol_handlers() {
        // 设置协议相关的信号处理器
        handler_->register_handler(SIG_HANDSHAKE, 
            [this](int sig) {
                // 响应握手信号
                SignalHandler::send_signal(peer_pid_, SIG_HANDSHAKE);
            });
        
        handler_->register_handler(SIG_HEARTBEAT,
            [this](int sig) {
                // 心跳信号处理
                std::cout << "Heartbeat received from " << peer_pid_ << std::endl;
            });
    }
};

20.5 高级IPC同步机制

20.5.1 信号量同步

信号量用于进程间的同步和互斥。

cpp 复制代码
#include <sys/sem.h>
#include <sys/ipc.h>

/**
 * System V信号量集管理器
 * 
 * 核心特性:
 * 1. 信号量集合:包含多个信号量的集合
 * 2. 原子操作:PV操作是原子的
 * 3. 阻塞等待:可以阻塞等待信号量
 * 4. 超时机制:支持超时等待
 * 
 * 数学模型:
 * - 信号量集合:S = {s₁, s₂, ..., sₙ},其中sᵢ ≥ 0
 * - P操作:sᵢ ← sᵢ - 1,若sᵢ < 0则阻塞
 * - V操作:sᵢ ← sᵢ + 1,若有等待进程则唤醒
 * - 不变式:∀i, sᵢ ≥ -wᵢ,其中wᵢ是等待进程数
 */
class SystemVSemaphoreSet {
private:
    int semid_;           // 信号量集ID
    int sem_count_;       // 信号量数量
    key_t key_;          // IPC键值
    bool is_creator_;     // 是否为创建者
    
public:
    /**
     * 构造函数
     * 
     * 创建或打开信号量集
     */
    SystemVSemaphoreSet(key_t key, int sem_count, int flags = IPC_CREAT | 0666) 
        : semid_(-1), sem_count_(sem_count), key_(key), is_creator_(false) {
        
        // 创建信号量集
        semid_ = semget(key, sem_count, flags);
        if (semid_ < 0) {
            perror("semget failed");
            return;
        }
        
        // 初始化信号量(仅当创建时)
        if ((flags & IPC_CREAT) && (flags & IPC_EXCL)) {
            is_creator_ = true;
            initialize_semaphores();
        }
    }
    
    ~SystemVSemaphoreSet() {
        if (is_creator_ && semid_ >= 0) {
            semctl(semid_, 0, IPC_RMID);
        }
    }
    
    /**
     * 初始化所有信号量
     * 
     * 使用SETALL命令一次性设置所有信号量的值
     */
    bool initialize_semaphores(unsigned short initial_value = 1) {
        if (semid_ < 0) return false;
        
        std::vector<unsigned short> values(sem_count_, initial_value);
        union semun arg;
        arg.array = values.data();
        
        if (semctl(semid_, 0, SETALL, arg) < 0) {
            perror("semctl SETALL failed");
            return false;
        }
        
        return true;
    }
    
    /**
     * P操作(等待)
     * 
     * 原子地减少信号量的值
     * 若信号量值为负,则阻塞等待
     * 
     * 参数:
     * - sem_num:信号量编号(0到sem_count-1)
     * - blocking:是否阻塞等待
     * - timeout_ms:超时时间(毫秒),-1表示无限等待
     * 
     * 返回值:
     * - true:成功获得信号量
     * - false:失败或超时
     */
    bool wait(int sem_num = 0, bool blocking = true, int timeout_ms = -1) {
        if (semid_ < 0 || sem_num < 0 || sem_num >= sem_count_) {
            return false;
        }
        
        struct sembuf sb;
        sb.sem_num = sem_num;
        sb.sem_op = -1;  // P操作
        sb.sem_flg = blocking ? 0 : IPC_NOWAIT;
        
        if (timeout_ms > 0) {
            // 使用semtimedop进行超时等待(需要Linux支持)
            timespec timeout;
            timeout.tv_sec = timeout_ms / 1000;
            timeout.tv_nsec = (timeout_ms % 1000) * 1000000;
            
            #ifdef __linux__
            if (semtimedop(semid_, &sb, 1, &timeout) < 0) {
                if (errno == EAGAIN) {
                    return false; // 超时
                }
                perror("semtimedop failed");
                return false;
            }
            #else
            // 非Linux系统使用轮询方式
            return wait_with_poll(sem_num, timeout_ms);
            #endif
        } else {
            // 普通semop操作
            if (semop(semid_, &sb, 1) < 0) {
                if (errno == EAGAIN) {
                    return false; // 非阻塞模式下信号量不可用
                }
                perror("semop failed");
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * V操作(释放)
     * 
     * 原子地增加信号量的值
     * 如果有进程在等待该信号量,则唤醒其中一个
     */
    bool signal(int sem_num = 0) {
        if (semid_ < 0 || sem_num < 0 || sem_num >= sem_count_) {
            return false;
        }
        
        struct sembuf sb;
        sb.sem_num = sem_num;
        sb.sem_op = 1;   // V操作
        sb.sem_flg = 0;
        
        if (semop(semid_, &sb, 1) < 0) {
            perror("semop signal failed");
            return false;
        }
        
        return true;
    }
    
    /**
     * 获取信号量值
     */
    int get_value(int sem_num = 0) const {
        if (semid_ < 0 || sem_num < 0 || sem_num >= sem_count_) {
            return -1;
        }
        
        return semctl(semid_, sem_num, GETVAL);
    }
    
    /**
     * 获取信号量信息
     */
    struct SemaphoreInfo {
        int sem_count;           // 信号量数量
        key_t key;               // IPC键值
        int creator_pid;         // 创建者PID
        int last_op_pid;         // 最后操作的PID
        time_t last_op_time;     // 最后操作时间
        time_t create_time;      // 创建时间
    };
    
    SemaphoreInfo get_info() const {
        SemaphoreInfo info = {};
        if (semid_ < 0) return info;
        
        semid_ds sem_info;
        union semun arg;
        arg.buf = &sem_info;
        
        if (semctl(semid_, 0, IPC_STAT, arg) < 0) {
            perror("semctl IPC_STAT failed");
            return info;
        }
        
        info.sem_count = sem_count_;
        info.key = key_;
        info.creator_pid = sem_info.sem_perm.cuid;
        info.last_op_pid = sem_info.sem_otime ? sem_info.sem_lpid : 0;
        info.last_op_time = sem_info.sem_otime;
        info.create_time = sem_info.sem_ctime;
        
        return info;
    }
    
private:
    /**
     * 轮询等待(用于不支持semtimedop的系统)
     */
    bool wait_with_poll(int sem_num, int timeout_ms) {
        auto start = std::chrono::steady_clock::now();
        
        while (true) {
            struct sembuf sb;
            sb.sem_num = sem_num;
            sb.sem_op = -1;
            sb.sem_flg = IPC_NOWAIT;
            
            if (semop(semid_, &sb, 1) == 0) {
                return true; // 成功获得信号量
            }
            
            if (errno != EAGAIN) {
                perror("semop failed");
                return false;
            }
            
            // 检查超时
            auto now = std::chrono::steady_clock::now();
            auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
                now - start).count();
            
            if (elapsed >= timeout_ms) {
                return false; // 超时
            }
            
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
};

/**
 * 基于信号量的进程同步示例
 */
class ProcessSynchronization {
private:
    std::unique_ptr<SystemVSemaphoreSet> sem_set_;
    
public:
    /**
     * 创建生产者-消费者同步
     * 
     * 信号量分配:
     * - sem[0]:互斥信号量(保护缓冲区)
     * - sem[1]:空槽位信号量(缓冲区空槽数量)
     * - sem[2]:满槽位信号量(缓冲区满槽数量)
     */
    bool setup_producer_consumer(int buffer_size) {
        key_t key = ftok("/tmp/prod_cons.key", 'P');
        if (key < 0) {
            perror("ftok failed");
            return false;
        }
        
        // 创建3个信号量的集合
        sem_set_ = std::make_unique<SystemVSemaphoreSet>(key, 3);
        if (!sem_set_ || !sem_set_->get_info().sem_count) {
            return false;
        }
        
        // 初始化信号量
        // sem[0] = 1 (互斥)
        sem_set_->get_semaphore_set()->initialize_semaphore(0, 1);
        // sem[1] = buffer_size (空槽位)
        sem_set_->get_semaphore_set()->initialize_semaphore(1, buffer_size);
        // sem[2] = 0 (满槽位)
        sem_set_->get_semaphore_set()->initialize_semaphore(2, 0);
        
        return true;
    }
    
    /**
     * 生产者操作
     * 
     * P(empty) → P(mutex) → 生产 → V(mutex) → V(full)
     */
    bool produce_item(const std::string& item, int timeout_ms = 5000) {
        if (!sem_set_) return false;
        
        // P(empty):等待空槽位
        if (!sem_set_->wait(1, true, timeout_ms)) {
            std::cerr << "等待空槽位超时" << std::endl;
            return false;
        }
        
        // P(mutex):进入临界区
        if (!sem_set_->wait(0, true, 1000)) {
            sem_set_->signal(1); // 回滚
            return false;
        }
        
        // 生产操作(临界区)
        std::cout << "生产项目: " << item << std::endl;
        
        // V(mutex):离开临界区
        sem_set_->signal(0);
        
        // V(full):增加满槽位
        sem_set_->signal(2);
        
        return true;
    }
    
    /**
     * 消费者操作
     * 
     * P(full) → P(mutex) → 消费 → V(mutex) → V(empty)
     */
    std::string consume_item(int timeout_ms = 5000) {
        if (!sem_set_) return "";
        
        // P(full):等待满槽位
        if (!sem_set_->wait(2, true, timeout_ms)) {
            std::cerr << "等待满槽位超时" << std::endl;
            return "";
        }
        
        // P(mutex):进入临界区
        if (!sem_set_->wait(0, true, 1000)) {
            sem_set_->signal(2); // 回滚
            return "";
        }
        
        // 消费操作(临界区)
        std::string item = "消费的项目";
        std::cout << "消费项目: " << item << std::endl;
        
        // V(mutex):离开临界区
        sem_set_->signal(0);
        
        // V(empty):增加空槽位
        sem_set_->signal(1);
        
        return item;
    }
};

20.5.2 共享内存同步

共享内存需要额外的同步机制来确保数据一致性。

cpp 复制代码
/**
 * 共享内存同步管理器
 * 
 * 结合共享内存和信号量实现进程间通信
 */
class SharedMemorySynchronization {
private:
    std::unique_ptr<SharedMemory> shared_mem_;      // 共享内存
    std::unique_ptr<SystemVSemaphoreSet> sem_set_;   // 同步信号量
    
public:
    /**
     * 同步模式定义
     */
    enum SyncMode {
        SYNC_READ_WRITE,    // 读写同步
        SYNC_READ_ONLY,      // 只读同步
        SYNC_WRITE_ONLY      // 只写同步
    };
    
    /**
     * 构造函数
     * 
     * 创建共享内存和同步信号量
     */
    SharedMemorySynchronization(const std::string& name, size_t size, SyncMode mode) {
        // 创建共享内存
        shared_mem_ = std::make_unique<SharedMemory>(name, size);
        if (!shared_mem_->create()) {
            throw std::runtime_error("创建共享内存失败");
        }
        
        // 创建同步信号量
        key_t key = ftok(name.c_str(), 'S');
        if (key < 0) {
            throw std::runtime_error("生成IPC键值失败");
        }
        
        // 根据同步模式创建信号量
        int sem_count = (mode == SYNC_READ_WRITE) ? 2 : 1;
        sem_set_ = std::make_unique<SystemVSemaphoreSet>(key, sem_count);
        
        if (!sem_set_->initialize_semaphores(1)) {
            throw std::runtime_error("初始化信号量失败");
        }
    }
    
    /**
     * 同步写操作
     * 
     * 确保写操作的互斥性和数据一致性
     */
    bool synchronized_write(size_t offset, const void* data, size_t size, int timeout_ms = 5000) {
        if (!shared_mem_ || !sem_set_) return false;
        
        // 获取写锁(信号量0)
        if (!sem_set_->wait(0, true, timeout_ms)) {
            return false;
        }
        
        // 执行写操作
        bool result = shared_mem_->write_data(offset, data, size);
        
        // 释放写锁
        sem_set_->signal(0);
        
        return result;
    }
    
    /**
     * 同步读操作
     * 
     * 确保读操作的数据一致性
     */
    bool synchronized_read(size_t offset, void* buffer, size_t size, int timeout_ms = 5000) const {
        if (!shared_mem_) return false;
        
        // 获取读锁(如果有的话)
        if (sem_set_ && sem_set_->get_info().sem_count > 1) {
            if (!sem_set_->wait(1, true, timeout_ms)) {
                return false;
            }
        }
        
        // 执行读操作
        bool result = shared_mem_->read_data(offset, buffer, size);
        
        // 释放读锁
        if (sem_set_ && sem_set_->get_info().sem_count > 1) {
            sem_set_->signal(1);
        }
        
        return result;
    }
    
    /**
     * 生产者-消费者模式
     * 
     * 使用共享内存实现高效的生产者-消费者通信
     */
    class ProducerConsumerBuffer {
    private:
        SharedMemorySynchronization* sync_mgr_;
        
        // 缓冲区结构定义
        struct BufferHeader {
            std::atomic<size_t> write_pos;    // 写位置
            std::atomic<size_t> read_pos;     // 读位置
            std::atomic<size_t> data_count;   // 数据计数
            size_t buffer_size;               // 缓冲区大小
            char data[];                      // 数据区(柔性数组)
        };
        
        BufferHeader* header_;                // 缓冲区头
        char* data_area_;                     // 数据区指针
        
    public:
        ProducerConsumerBuffer(SharedMemorySynchronization* sync_mgr) 
            : sync_mgr_(sync_mgr), header_(nullptr), data_area_(nullptr) {
            
            // 映射共享内存
            auto info = sync_mgr_->shared_mem_->get_info();
            if (info.is_mapped) {
                void* addr = sync_mgr_->shared_mem_->get_address();
                header_ = static_cast<BufferHeader*>(addr);
                data_area_ = header_->data;
            }
        }
        
        /**
         * 初始化缓冲区
         */
        bool initialize(size_t buffer_size) {
            if (!header_) return false;
            
            header_->write_pos = 0;
            header_->read_pos = 0;
            header_->data_count = 0;
            header_->buffer_size = buffer_size;
            
            return true;
        }
        
        /**
         * 生产数据
         */
        bool produce(const void* data, size_t size, int timeout_ms = 5000) {
            if (!header_ || !data_area_) return false;
            
            // 检查缓冲区是否有足够空间
            size_t available_space = header_->buffer_size - header_->data_count;
            if (size > available_space) {
                return false;
            }
            
            // 获取写锁
            sync_mgr_->sem_set_->wait(0, true, timeout_ms);
            
            // 写入数据
            size_t write_pos = header_->write_pos.load();
            memcpy(data_area_ + write_pos, data, size);
            
            // 更新写位置和计数
            header_->write_pos = (write_pos + size) % header_->buffer_size;
            header_->data_count += size;
            
            // 释放写锁
            sync_mgr_->sem_set_->signal(0);
            
            return true;
        }
        
        /**
         * 消费数据
         */
        bool consume(void* buffer, size_t size, int timeout_ms = 5000) {
            if (!header_ || !data_area_) return false;
            
            // 检查是否有足够数据
            if (header_->data_count < size) {
                return false;
            }
            
            // 获取读锁
            sync_mgr_->sem_set_->wait(1, true, timeout_ms);
            
            // 读取数据
            size_t read_pos = header_->read_pos.load();
            memcpy(buffer, data_area_ + read_pos, size);
            
            // 更新读位置和计数
            header_->read_pos = (read_pos + size) % header_->buffer_size;
            header_->data_count -= size;
            
            // 释放读锁
            sync_mgr_->sem_set_->signal(1);
            
            return true;
        }
        
        /**
         * 获取缓冲区状态
         */
        struct BufferStatus {
            size_t write_position;
            size_t read_position;
            size_t data_count;
            size_t buffer_size;
            size_t available_space;
            double utilization_rate;
        };
        
        BufferStatus get_status() const {
            BufferStatus status = {};
            if (header_) {
                status.write_position = header_->write_pos.load();
                status.read_position = header_->read_pos.load();
                status.data_count = header_->data_count.load();
                status.buffer_size = header_->buffer_size;
                status.available_space = header_->buffer_size - status.data_count;
                status.utilization_rate = static_cast<double>(status.data_count) / 
                                          header_->buffer_size * 100.0;
            }
            return status;
        }
    };
    
    /**
     * 创建生产者-消费者缓冲区
     */
    std::unique_ptr<ProducerConsumerBuffer> create_producer_consumer_buffer(size_t buffer_size) {
        auto buffer = std::make_unique<ProducerConsumerBuffer>(this);
        if (buffer->initialize(buffer_size)) {
            return buffer;
        }
        return nullptr;
    }
};

20.6 性能分析与优化

20.6.1 IPC机制性能比较

不同IPC机制的性能特征比较:

cpp 复制代码
/**
 * IPC性能测试框架
 */
class IPCPerformanceTest {
public:
    struct PerformanceMetrics {
        double throughput;           // 吞吐量(MB/s)
        double latency;              // 延迟(微秒)
        double cpu_usage;            // CPU使用率(%)
        size_t message_count;        // 消息数量
        size_t total_data_size;      // 总数据量(字节)
        std::chrono::microseconds duration; // 测试持续时间
    };
    
    /**
     * 测试管道性能
     */
    static PerformanceMetrics test_pipe_performance(size_t message_size, size_t message_count) {
        PerformanceMetrics metrics = {};
        auto start_time = std::chrono::high_resolution_clock::now();
        
        // 创建管道
        int pipefd[2];
        if (pipe(pipefd) < 0) {
            perror("pipe failed");
            return metrics;
        }
        
        // 准备测试数据
        std::vector<char> send_buffer(message_size, 'A');
        std::vector<char> recv_buffer(message_size);
        
        // 执行测试
        for (size_t i = 0; i < message_count; ++i) {
            // 写入数据
            if (write(pipefd[1], send_buffer.data(), message_size) != static_cast<ssize_t>(message_size)) {
                perror("write failed");
                break;
            }
            
            // 读取数据
            if (read(pipefd[0], recv_buffer.data(), message_size) != static_cast<ssize_t>(message_size)) {
                perror("read failed");
                break;
            }
        }
        
        auto end_time = std::chrono::high_resolution_clock::now();
        metrics.duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
        
        // 计算性能指标
        metrics.message_count = message_count;
        metrics.total_data_size = message_size * message_count;
        metrics.throughput = (metrics.total_data_size * 1000000.0) / (1024.0 * 1024.0 * metrics.duration.count());
        metrics.latency = static_cast<double>(metrics.duration.count()) / message_count;
        
        close(pipefd[0]);
        close(pipefd[1]);
        
        return metrics;
    }
    
    /**
     * 测试共享内存性能
     */
    static PerformanceMetrics test_shared_memory_performance(size_t message_size, size_t message_count) {
        PerformanceMetrics metrics = {};
        auto start_time = std::chrono::high_resolution_clock::now();
        
        // 创建共享内存
        SharedMemory shared_mem("/perf_test", message_size * 2);
        if (!shared_mem.create()) {
            return metrics;
        }
        
        // 准备测试数据
        std::vector<char> send_buffer(message_size, 'B');
        std::vector<char> recv_buffer(message_size);
        
        // 执行测试
        for (size_t i = 0; i < message_count; ++i) {
            size_t offset = (i % 2) * message_size;
            
            // 写入数据
            shared_mem.write_data(offset, send_buffer.data(), message_size);
            
            // 读取数据
            shared_mem.read_data(offset, recv_buffer.data(), message_size);
        }
        
        auto end_time = std::chrono::high_resolution_clock::now();
        metrics.duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
        
        // 计算性能指标
        metrics.message_count = message_count;
        metrics.total_data_size = message_size * message_count * 2; // 读写双向
        metrics.throughput = (metrics.total_data_size * 1000000.0) / (1024.0 * 1024.0 * metrics.duration.count());
        metrics.latency = static_cast<double>(metrics.duration.count()) / message_count;
        
        return metrics;
    }
    
    /**
     * 综合性能测试
     */
    static void comprehensive_performance_test() {
        std::vector<size_t> message_sizes = {64, 256, 1024, 4096, 16384, 65536};
        std::vector<size_t> message_counts = {1000, 10000, 100000};
        
        std::cout << "\n=== IPC性能综合测试 ===" << std::endl;
        std::cout << std::setw(12) << "消息大小" 
                  << std::setw(12) << "消息数量"
                  << std::setw(15) << "机制"
                  << std::setw(15) << "吞吐量(MB/s)"
                  << std::setw(15) << "延迟(μs)"
                  << std::endl;
        std::cout << std::string(80, '-') << std::endl;
        
        for (size_t msg_size : message_sizes) {
            for (size_t msg_count : message_counts) {
                // 测试管道性能
                auto pipe_metrics = test_pipe_performance(msg_size, msg_count);
                std::cout << std::setw(12) << msg_size
                          << std::setw(12) << msg_count
                          << std::setw(15) << "管道"
                          << std::setw(15) << std::fixed << std::setprecision(2) << pipe_metrics.throughput
                          << std::setw(15) << std::fixed << std::setprecision(2) << pipe_metrics.latency
                          << std::endl;
                
                // 测试共享内存性能
                auto shm_metrics = test_shared_memory_performance(msg_size, msg_count);
                std::cout << std::setw(12) << msg_size
                          << std::setw(12) << msg_count
                          << std::setw(15) << "共享内存"
                          << std::setw(15) << std::fixed << std::setprecision(2) << shm_metrics.throughput
                          << std::setw(15) << std::fixed << std::setprecision(2) << shm_metrics.latency
                          << std::endl;
                
                std::cout << std::string(80, '-') << std::endl;
            }
        }
    }
};

20.7 实践练习

20.7.1 基础练习

  1. 管道通信实现:实现一个父子进程通信系统,父进程发送命令,子进程执行并返回结果。

  2. 共享内存设计:设计一个多进程共享的环形缓冲区,支持并发读写操作。

  3. 信号处理程序:编写一个信号处理程序,能够捕获并处理SIGINT、SIGTERM等常见信号。

20.7.2 进阶项目

  1. 多进程文件处理系统

    • 使用管道进行进程间通信
    • 实现文件分块处理
    • 支持进度报告和错误处理
    • 包含完整的同步机制
  2. 高性能网络服务框架

    • 基于共享内存的缓存系统
    • 多进程并发处理模型
    • 进程间状态同步
    • 性能监控和统计
  3. 分布式计算引擎

    • 任务分发和结果收集
    • 进程间负载均衡
    • 故障检测和恢复
    • 资源管理和调度

20.7.3 理论分析题

  1. 比较分析:对比不同IPC机制的性能特征,分析其适用场景和限制条件。

  2. 死锁预防:设计一个死锁预防算法,适用于多进程共享资源环境。

  3. 一致性模型:分析共享内存系统中的一致性问题,提出解决方案。

20.8 学习评估

完成本章节后,你应该能够:

理解进程间通信的基本概念和分类

掌握管道、命名管道、消息队列的使用方法

熟练使用共享内存进行高效数据交换

理解信号机制和处理方法

掌握进程同步的基本原理和技术

能够设计和实现复杂的IPC系统

具备IPC性能分析和优化能力

参考文献

  1. Stevens, W. R. (1999). UNIX Network Programming, Volume 2: Interprocess Communications. Prentice Hall.
  2. Stevens, W. R., & Rago, S. A. (2013). Advanced Programming in the UNIX Environment. Addison-Wesley.
  3. Butenhof, D. R. (1997). Programming with POSIX Threads. Addison-Wesley.
  4. Kleiman, S., Shah, D., & Smaalders, B. (1995). Programming with Threads. SunSoft Press.
  5. ISO/IEC 9945:2009 - IEEE Std 1003.1-2008 (POSIX.1)
  6. Linux man pages - pipe(2), shm_open(3), semget(2), sigaction(2)
相关推荐
赖small强1 小时前
【Linux C/C++开发】第24章:现代C++特性(C++17/20)核心概念
linux·c语言·c++·c++17/20
SundayBear1 小时前
嵌入式操作系统进阶C语言
c语言·开发语言·嵌入式
-森屿安年-2 小时前
LeetCode 11. 盛最多水的容器
开发语言·c++·算法·leetcode
ouliten2 小时前
C++笔记:std::stringbuf
开发语言·c++·笔记
Robpubking2 小时前
elasticsearch 使用 systemd 启动时卡在 starting 状态 解决过程记录
linux·运维·elasticsearch
hlsd#3 小时前
我把自己的小米ax3000t换成了OpenWRT
linux·iot
不想画图3 小时前
Linux——web服务介绍和nginx编译安装
linux·nginx
2301_807583233 小时前
ubuntu22.04集群部署clickhouse详细步骤
linux·clickhouse·zookeeper
尹蓝锐3 小时前
Linux解压各种压缩包命令
linux·运维·服务器