首页 > 系统相关 >进程间通信(IPC):概念、分类与信号机制(2)

进程间通信(IPC):概念、分类与信号机制(2)

时间:2024-09-06 17:20:36浏览次数:7  
标签:IPC int 分类 间通信 信号 printf 进程 include

文章目录


进程间通信(IPC):概念、分类与信号机制

引言

进程间通信(Inter-Process Communication,IPC)是指两个或多个进程之间交换数据和信息的机制。由于操作系统的进程是相互独立的,必须通过IPC来实现数据交换和信号通知。IPC在多进程应用程序中至关重要,尤其是在需要协作和同步的场景中。

IPC的分类

进程间通信的方法可以分类为以下几种:

  1. 信号:一种简单的通知机制,用于异步地通知进程某个事件的发生。
  2. 管道:提供一个简单的单向通信通道,允许一个进程将输出通过管道传递给另一个进程。
  3. 共享文件:多个进程可以通过访问同一个文件来交换数据。
  4. 消息队列:一种先进先出(FIFO)机制,允许进程以消息的方式进行通信。
  5. 共享内存:多个进程可以访问同一块内存区域以交换数据。
  6. 网络通信:通过网络连接的进程可以使用网络协议进行通信。

信号机制

信号是操作系统提供的一种异步通信机制,允许进程通知另一个进程(或自己)发生了某些事件。信号的机制包括以下几个部分:

信号周期

信号的生命周期可以分为几个阶段:

  1. 发送:由某个进程(发送者)发送信号。
  2. 接收:目标进程(接收者)接收信号。
  3. 处理:接收进程根据设置的信号处理程序处理信号。
  4. 注销:信号处理完成后,信号将被注销。

信号的产生

信号可以通过以下方式产生:

  1. 系统事件:某些系统事件(如除零错误、非法内存访问等)会自动生成信号。
  2. 发送信号:进程可以使用诸如kill()raise()abort()alarm()setitimer()等系统调用显式发送信号。

信号的发送

以下是一些发送信号的示例:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handler(int signum) {
    printf("接收到信号 %d\n", signum);
}

int main() {
    signal(SIGUSR1, handler); // 注册信号处理程序

    pid_t pid = fork();
    if (pid == 0) {
        // 子进程
        sleep(1); // 等待父进程注册处理程序
        kill(getppid(), SIGUSR1); // 向父进程发送信号
        _exit(0);
    } else {
        // 父进程
        pause(); // 等待信号
    }

    return 0;
}

信号的接收

接收信号的过程涉及到信号处理:

  • 信号处理:可以使用signal()sigaction()来指定信号的处理程序。
  • pause:调用后,进程将挂起直至接收到任何信号,常用于等待信号的到来。

信号处理示例

以下是一个使用sigaction进行信号处理的示例:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void handler(int signum) {
    printf("处理信号 %d\n", signum);
}

int main() {
    struct sigaction sa;
    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    sigaction(SIGINT, &sa, NULL); // 注册SIGINT信号处理程序

    printf("按 Ctrl+C 发送信号...\n");
    while (1) {
        pause(); // 等待信号
    }

    return 0;
}

IPC的其他方法

管道通信

管道是一种简单的单向通信机制,允许一个进程将输出通过管道传递给另一个进程。以下是一个使用管道进行进程间通信的示例:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
    int pipefd[2];
    char buffer[20];

    if (pipe(pipefd) == -1) {
        perror("管道创建失败");
        exit(EXIT_FAILURE);
    }

    if (fork() == 0) {
        // 子进程
        close(pipefd[1]); // 关闭写端
        read(pipefd[0], buffer, sizeof(buffer)); // 从管道读取数据
        printf("子进程接收到: %s\n", buffer);
        close(pipefd[0]);
        exit(0);
    } else {
        // 父进程
        close(pipefd[0]); // 关闭读端
        const char *msg = "Hello, IPC!";
        write(pipefd[1], msg, sizeof(msg)); // 向管道写入数据
        close(pipefd[1]);
        wait(NULL); // 等待子进程结束
    }

    return 0;
}

消息队列

消息队列允许进程以消息的方式进行通信,支持优先级和异步处理。以下是一个使用消息队列的示例:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <unistd.h>

#define MSG_SIZE 100

struct msg_buffer {
    long msg_type;
    char msg_text[MSG_SIZE];
};

int main() {
    key_t key = ftok("progfile", 65); // 创建唯一键
    int msgid = msgget(key, 0666 | IPC_CREAT); // 创建消息队列

    if (fork() == 0) {
        // 子进程
        struct msg_buffer message;
        message.msg_type = 1;
        strcpy(message.msg_text, "Hello from child!");
        msgsnd(msgid, &message, sizeof(message), 0); // 发送消息
        exit(0);
    } else {
        // 父进程
        struct msg_buffer message;
        msgrcv(msgid, &message, sizeof(message), 1, 0); // 接收消息
        printf("父进程接收到: %s\n", message.msg_text);
        msgctl(msgid, IPC_RMID, NULL); // 删除消息队列
    }

    return 0;
}

共享内存

共享内存允许多个进程访问同一块内存区域以交换数据。以下是一个使用共享内存的示例:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <string.h>

#define SHM_SIZE 1024

int main() {
    key_t key = ftok("shmfile", 65); // 创建唯一键
    int shmid = shmget(key, SHM_SIZE, 0666 | IPC_CREAT); // 创建共享内存

    if (fork() == 0) {
        // 子进程
        char *str = (char *)shmat(shmid, NULL, 0); // 连接共享内存
        strcpy(str, "Hello from child!"); // 写入数据
        shmdt(str); // 断开连接
        exit(0);
    } else {
        // 父进程
        char *str = (char *)shmat(shmid, NULL, 0); // 连接共享内存
        printf("父进程接收到: %s\n", str); // 读取数据
        shmdt(str); // 断开连接
        shmctl(shmid, IPC_RMID, NULL); // 删除共享内存
    }

    return 0;
}

套接字通信

套接字是一种网络通信机制,允许不同主机上的进程进行通信。以下是一个简单的TCP套接字通信示例:

服务器端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};

    // 创建套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("套接字创建失败");
        exit(EXIT_FAILURE);
    }

    // 绑定套接字
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);
    bind(server_fd, (struct sockaddr *)&address, sizeof(address));

    // 监听连接
    listen(server_fd, 3);
    printf("等待连接...\n");
    new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen);
    printf("连接成功\n");

    // 读取数据
    read(new_socket, buffer, 1024);
    printf("接收到: %s\n", buffer);
    close(new_socket);
    close(server_fd);
    return 0;
}
客户端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080

int main() {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char *message = "Hello from client!";

    // 创建套接字
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("\n套接字创建失败\n");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // 转换IPv4地址
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        printf("\n无效地址/地址不支持\n");
        return -1;
    }

    // 连接到服务器
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        printf("\n连接失败\n");
        return -1;
    }

    // 发送数据
    send(sock, message, strlen(message), 0);
    printf("消息已发送\n");
    close(sock);
    return 0;
}

优点与缺点

优点

  • 简单性:信号机制设计简单、易于实现,适合快速响应异步事件。
  • 实时性:信号机制能够快速传递重要事件通知。
  • 多样性:IPC提供多种方式,适应不同的应用场景。
  • 高效性:共享内存和管道等机制在数据传输时具有较高的效率。

缺点

  • 有限数据量:信号不能传递复杂数据,仅能传递简单的命令或通知。
  • 处理复杂性:信号处理的设计可能导致进程状态不可预测(如死锁、资源竞争等)。
  • 性能开销:某些IPC机制(如消息队列和共享内存)可能引入额外的性能开销。
  • 安全性问题:IPC机制可能面临安全性问题,如数据泄露和未授权访问。

结论

进程间通信是现代操作系统的重要组成部分,信号作为一种轻量级的IPC机制,适用于简单的事件通知。了解不同的IPC方法及其优缺点,能够有效地选择适合特定需求的通信机制,为进程间的数据交换和协作提供支持。
在实际应用中,选择合适的IPC机制取决于具体的需求,如数据传输的复杂性、实时性要求、系统资源的使用等。


标签:IPC,int,分类,间通信,信号,printf,进程,include
From: https://blog.csdn.net/weixin_65477256/article/details/141965109

相关文章

  • Python贝叶斯卷积神经网络BCNN分类胸部X光图像数据集实例
    全文链接:https://tecdat.cn/?p=37604原文出处:拓端数据部落公众号分析师:YuanchunNiu在人工智能的诸多领域中,分类技术扮演着核心角色,其应用广泛而深远。无论是在金融风险评估、医疗诊断、安全监控还是日常的交互式服务中,有效的分类算法都是实现智能决策的关键。随着大数据时代的......
  • JAVA三级分类的使用
    1.0准备1.创建好一个java文件2.导入所需要的包(至少29个)3.创建resources包并标记为资源根目录,配置好框架配置信息web.xml4.创建pojo包,编写实体类pojo 5.创建mapper包,编写接口mapper 6.编写实现类mapper.xml  7.创建service包,编写service以及impl8.编写测试......
  • 6、显卡品牌分类介绍:微星 - 计算机硬件品牌系列文章
    微星科技是一家知名的电脑硬件制造商,‌特别是在显卡和主板领域有着显著的影响力。‌该公司成立于1986年8月,‌总部位于上海市延安西路889号太平洋中心三楼。‌微星科技早期以主板、‌显卡为主要产品,‌与技嘉、‌华硕等齐名,‌为主板三大厂之一。‌近年来,‌微星向电竞个人电脑市......
  • 【事件IO分类】什么是慢IO事件,什么是快IO事件?
    在大家耳熟能详的事件驱动框架,比如libeventlibevlibuv等,其中都会对IO进行分类,从而更高效的进行处理,而不阻塞整体运行流程。慢IO,顾名思义。就是IO会长时间阻塞,比如:DNS解析。DNS(域名系统)解析通常被认为是一种慢的I/O操作,原因主要有以下几点:###1.网络延迟DNS解析涉及......
  • PMP–一、二、三模、冲刺、必刷–分类–14.敏捷–技巧--累积流图
    文章目录技巧一模二模三模14.敏捷–敏捷团队的衡量结果–累积流图:1、敏捷项目的项目经理担心团队在最近的迭代中失去了动力。项目经理应该使用哪两种工具来分析团队绩效?(选择两个)冲刺必刷7.成本管理--挣值分析燃尽图仅能了解进度,不能了解成本29、[单选]一家公司正在......
  • [苍穹外卖]-03分类管理模块开发
    效果预览需求分析查看产品原型:根据原型分析业务规则业务规则分类名称必须是唯一的分类按照类型可以分为菜品分类和套餐分类新添加的分类状态默认为"禁用"接口设计该模块涉及6个接口:新增分类/分类分页查询/根据id删除分类/修改分类/启用禁用分类/根据类型查询分类......
  • 【机器学习】任务三:基于逻辑回归与线性回归的鸢尾花分类与波士顿房价预测分析
    目录1.目的和要求1.1掌握回归分析的概念和使用场景1.2 掌握机器学习回归分析进行数据预测的有效方法1.3 掌握特征重要性分析、特征选择和模型优化的方法2.波士顿房价预测与特征分析2.1第一步:导入所需的模块和包2.2第二步:加载波士顿房价数据集2.3第三步:数据预处理......
  • codetop算法分类
    以下是按照常见算法标签将题目进行归类的列表:1.动态规划10.正则表达式匹配1143.最长公共子序列115.不同的子序列120.三角形最小路径和121.买卖股票的最佳时机123.买卖股票的最佳时机III131.分割回文串152.乘积最大子数组188.买卖股票的最佳时机IV198.打家......
  • 回归、分类、生成三大任务实现原理
    在机器学习与深度学习相关项目需求实现中,通常可以细分成很多个回归、分类、生成任务的实现,由这些任务组成一个完整的任务。下面分别介绍这三种任务回归:什么是回归?找到一个函数,通过输入的特征值X,输出一个连续的数值Y。回归任务的目标是预测连续值的输出。例如,预测房价、温度......
  • 操作系统体系结构分类
    目录大内核(宏内核)微内核分层结构模块化外核大内核(宏内核)定义:大内核体系结构将所有系统功能集成在操作系统内核中,包括进程管理、内存管理、文件系统、网络协议等。优点:高性能:由于系统调用和内核服务可以直接在内核态中完成,减少了用户态与内核态之间的切换开销,提高了......