面试问题--进程间通信

进程间通信的C语言实现

在操作系统中,进程间通信(IPC)是一种重要的机制,允许不同的进程之间进行数据交换和信息传递。本文将介绍几种常见的进程间通信方式,并提供用C语言实现的简单示例。

1. 管道(Pipes)

  • 说明: 管道是一种单向通信机制,允许一个进程的输出直接作为另一个进程的输入。
  • 示例: 在Unix/Linux系统中,可以使用pipe函数创建一个管道,通过fork创建子进程,使得子进程的输出可以传递给父进程。例如,一个进程可以生成一些数据,将其通过管道传递给另一个进程进行处理。
c 复制代码
#include <stdio.h>
#include <unistd.h>

int main() {
    int pipe_fd[2];
    char buffer[30];

    // 创建管道
    if (pipe(pipe_fd) == -1) {
        perror("pipe");
        return 1;
    }

    // 创建子进程
    pid_t pid = fork();

    if (pid == -1) {
        perror("fork");
        return 1;
    }

    if (pid == 0) { // 子进程
        close(pipe_fd[1]); // 关闭写入端

        // 从管道读取数据
        read(pipe_fd[0], buffer, sizeof(buffer));
        printf("Child Process: Received message from parent: %s\n", buffer);

        close(pipe_fd[0]);
    } else { // 父进程
        close(pipe_fd[0]); // 关闭读取端

        const char* message = "Hello from Parent Process!";
        
        // 将数据写入管道
        write(pipe_fd[1], message, strlen(message) + 1);

        close(pipe_fd[1]);
    }

    return 0;
}

2. 消息队列(Message Queues):

  • 说明: 消息队列允许进程通过在队列中发送和接收消息来进行通信。消息队列是一种通过消息进行异步通信的机制。
  • 示例: 在Linux中,使用msgget创建消息队列,msgsnd发送消息,msgrcv接收消息。例如,一个进程可以将消息发送到队列中,而另一个进程可以从队列中接收并处理这些消息。
c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

struct message {
    long msg_type;
    char msg_text[100];
};

int main() {
    key_t key;
    int msg_id;

    // 创建唯一的键值
    key = ftok("msg_queue_key", 65);

    // 创建消息队列
    msg_id = msgget(key, 0666 | IPC_CREAT);

    struct message msg;

    // 发送消息
    msg.msg_type = 1;
    strcpy(msg.msg_text, "Hello from Message Queue!");
    msgsnd(msg_id, &msg, sizeof(msg), 0);

    printf("Message Sent: %s\n", msg.msg_text);

    return 0;
}

3. 共享内存(Shared Memory):

  • 说明: 共享内存允许多个进程访问同一块内存空间,从而实现数据共享。因为进程可以直接读写共享内存,所以这是一种高效的通信方式。
  • 示例: 通过shmget创建共享内存,shmat将共享内存映射到进程的地址空间。多个进程可以通过共享内存读写数据。例如,一个进程可以将数据写入共享内存,而另一个进程可以读取这些数据。
c 复制代码
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main() {
    key_t key;
    int shmid;
    char* data;

    // 创建唯一的键值
    key = ftok("shared_memory_key", 65);

    // 创建共享内存
    shmid = shmget(key, 1024, 0666 | IPC_CREAT);

    // 将共享内存连接到当前进程的地址空间
    data = (char*)shmat(shmid, (void*)0, 0);

    // 写入数据到共享内存
    sprintf(data, "Hello from Shared Memory!");

    printf("Data Written: %s\n", data);

    // 分离共享内存
    shmdt(data);

    return 0;
}

4. 套接字(Sockets):

  • 说明: 套接字是一种网络通信机制,但它也可以用于本地进程间通信。套接字提供了一种通用的双向通信方式,适用于不同主机或同一主机上的不同进程。
  • 示例: 进程可以通过套接字进行网络通信,也可以在本地使用套接字进行进程间通信。例如,两个进程可以通过套接字在同一台计算机上进行通信,实现数据交换和协作。
c 复制代码
#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 addrlen = sizeof(address);
    char buffer[1024] = {0};
    const char* hello = "Hello from Socket!";

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

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    // 绑定套接字到地址和端口
    if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 监听连接
    if (listen(server_fd, 3) < 0) {
        perror("listen failed");
        exit(EXIT_FAILURE);
    }

    // 接受连接
    if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {
        perror("accept failed");
        exit(EXIT_FAILURE);
    }

    // 发送数据
    send(new_socket, hello, strlen(hello), 0);
    printf("Message Sent: %s\n", hello);

    close(new_socket);
    close(server_fd);

    return 0;
}

5. 信号(Signals):

  • 说明: 信号是一种异步通信机制,用于通知进程发生了某种事件。信号常用于处理外部事件,如用户输入或错误发生。
  • 示例: 进程可以通过向另一个进程发送信号来通知某个事件的发生。例如,kill命令可以向进程发送信号,常用于终止一个进程。
c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void signal_handler(int signum) {
    if (signum == SIGUSR1) {
        printf("Received SIGUSR1 signal.\n");
    }
}

int main() {
    // 注册信号处理函数
    signal(SIGUSR1, signal_handler);

    // 发送信号给当前进程
    kill(getpid(), SIGUSR1);

    return 0;
}
相关推荐
lldhsds4 分钟前
书生大模型实战营第四期-入门岛-1. Linux前置基础
linux
cuisidong199719 分钟前
5G学习笔记三之物理层、数据链路层、RRC层协议
笔记·学习·5g
乌恩大侠21 分钟前
5G周边知识笔记
笔记·5g
wowocpp27 分钟前
ubuntu 22.04 硬件配置 查看 显卡
linux·运维·ubuntu
山河君39 分钟前
ubuntu使用DeepSpeech进行语音识别(包含交叉编译)
linux·ubuntu·语音识别
鹏大师运维43 分钟前
【功能介绍】信创终端系统上各WPS版本的授权差异
linux·wps·授权·麒麟·国产操作系统·1024程序员节·统信uos
xinghuitunan44 分钟前
蓝桥杯顺子日期(填空题)
c语言·蓝桥杯
筱源源1 小时前
Elasticsearch-linux环境部署
linux·elasticsearch
Half-up1 小时前
C语言心型代码解析
c语言·开发语言
懒大王就是我1 小时前
C语言网络编程 -- TCP/iP协议
c语言·网络·tcp/ip