linux 进程间通信和信号处理

发布时间 2023-08-07 21:03:07作者: 云淡#风清

进程间通信(Interprocess Communication,IPC)和信号处理是Linux系统中用于实现不同进程之间数据交换和协调的重要机制。以下是关于这两个概念的详细解释,并附带示例说明:

  1. 进程间通信(IPC):

    • 管道(Pipe):管道是一种半双工通信方式,可用于在父子进程之间传递数据。一个进程将数据写入管道,另一个进程从管道中读取数据。示例:在命令行中执行 ls | grep .txt,将ls的输出通过管道传递给grep进行过滤。

    • 消息队列(Message Queue):消息队列允许进程通过消息进行通信,每个消息都有优先级和类型。示例:两个进程之间使用消息队列来交换数据,如进程A向进程B发送一条消息。

    • 共享内存(Shared Memory):多个进程可以映射到同一块物理内存,实现高效的数据共享。示例:多个进程可以通过共享内存来共享一个计数器,实现并发计数。

    • 信号量(Semaphore):信号量用于控制多个进程对共享资源的访问,可以用于进程同步和互斥。示例:使用信号量来限制同时访问某个共享文件的进程数量。

  2. 信号处理:

    • SIGTERM:终止信号,通知进程要求它优雅地终止。示例:在终端中使用 kill PID 命令发送SIGTERM信号来终止进程。

    • SIGINT:终端中断信号,通常由Ctrl+C触发,用于中断正在执行的进程。示例:在终端中按下Ctrl+C中断正在运行的程序。

    • SIGKILL:杀死信号,强制终止进程,无法被捕获或忽略。示例:使用 kill -9 PID 命令发送SIGKILL信号来强制终止进程。

    • SIGUSR1 和 SIGUSR2:用户定义的信号,可以用于进程之间自定义通信。示例:进程A通过发送SIGUSR1信号来通知进程B执行特定操作。

  3. 套接字(Socket): 套接字是一种用于进程间通信的强大机制,不仅适用于本地进程通信,还可以在网络上实现进程之间的通信。套接字可以用于建立客户端-服务器模型,允许不同主机上的进程进行数据交换。示例:通过套接字在两台计算机之间传输文件或数据。

  4. 信号处理的示例: 假设有一个简单的C程序,我们希望在收到SIGINT信号(通常由Ctrl+C触发)时进行特定操作,比如打印一条消息然后退出。

    #include <stdio.h>
    #include <signal.h>
    #include <unistd.h>
    
    void sigint_handler(int signum) {
        printf("收到SIGINT信号,正在退出...\n");
        _exit(0);
    }
    
    int main() {
        // 注册信号处理函数
        signal(SIGINT, sigint_handler);
    
        printf("运行中,请按Ctrl+C终止...\n");
    
        while (1) {
            // 模拟进程工作
            sleep(1);
        }
    
        return 0;
    }

在这个示例中,当程序运行时,如果用户按下Ctrl+C,就会收到SIGINT信号,然后调用sigint_handler函数来处理信号,输出一条消息并退出程序。

使用共享内存进行进程间通信的示例: 假设有两个进程,一个进程写入数据到共享内存,另一个进程读取数据。以下是一个简单的示例:

进程A(写入数据):

#include <stdio.h>
#include <sys/shm.h>
#include <string.h>

int main() {
    key_t key = ftok("shmfile", 65);
    int shmid = shmget(key, 1024, 0666|IPC_CREAT);
    char *str = (char*) shmat(shmid, (void*)0, 0);

    strcpy(str, "Hello, shared memory!");

    shmdt(str);
    return 0;
}

进程B(读取数据):

#include <stdio.h>
#include <sys/shm.h>

int main() {
    key_t key = ftok("shmfile", 65);
    int shmid = shmget(key, 1024, 0666|IPC_CREAT);
    char *str = (char*) shmat(shmid, (void*)0, 0);

    printf("从共享内存读取的数据:%s\n", str);

    shmdt(str);
    shmctl(shmid, IPC_RMID, NULL);
    return 0;
}

这个示例中,进程A将数据写入共享内存,进程B从共享内存读取数据,并在完成后删除共享内存。