进程与线程(四)——进程间通信

C语言中的进程通信(Inter-Process Communication,IPC)方法主要有以下几种,每种方法适用于不同的应用场景。下面将详细介绍这些方法:

1. 管道(Pipe)

管道是一种允许进程间传递数据的机制,具有以下特点:

  • 无名管道(Anonymous Pipe):通常用于父子进程或兄弟进程之间,传输数据的方向是单向的。
  • 有名管道(Named Pipe):允许在无亲缘关系的进程间进行通信,且在文件系统中有路径,数据可以是双向的。
无名管道的基本用法:
  • 使用pipe()创建管道。
  • 使用write()read()在管道两端进行数据传输。
代码示例:
#include <stdio.h>
#include <unistd.h>

int main() {
    int pipefd[2];
    pid_t pid;
    char buf[20];

    // 创建管道
    pipe(pipefd);

    pid = fork();
    if (pid > 0) {  // 父进程
        close(pipefd[0]);  // 关闭读取端
        write(pipefd[1], "Hello from parent", 18);  // 向管道写入数据
        close(pipefd[1]);
    } else if (pid == 0) {  // 子进程
        close(pipefd[1]);  // 关闭写入端
        read(pipefd[0], buf, sizeof(buf));  // 从管道读取数据
        printf("Child received: %s\n", buf);
        close(pipefd[0]);
    }
    return 0;
}

2. 信号(Signal)

信号是操作系统用来通知进程发生特定事件的一种方式。信号可以由内核或其他进程发送,用于中断进程的正常执行流或通知事件的发生。常用的信号包括SIGINTSIGTERMSIGKILL等。

信号的基本用法:
  • 使用signal()sigaction()来设置信号处理函数。
  • 使用kill()raise()来发送信号。
代码示例:
#include <stdio.h>
#include <signal.h>

void handler(int sig) {
    printf("Received signal %d\n", sig);
}

int main() {
    signal(SIGINT, handler);  // 设置SIGINT信号处理函数
    while (1) {
        printf("Running...\n");
        sleep(1);
    }
    return 0;
}

3. 消息队列(Message Queue)

消息队列是进程间通信的一种形式,允许进程将数据以消息的形式放入队列中,其他进程可以从队列中读取数据。消息队列适用于需要发送结构化数据的情况。

消息队列的基本用法:
  • 使用msgget()创建消息队列。
  • 使用msgsnd()向消息队列发送消息。
  • 使用msgrcv()从消息队列接收消息。
代码示例:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

struct msgbuf {
    long mtype;
    char mtext[100];
};

int main() {
    key_t key = ftok("msgfile", 65);
    int msgid = msgget(key, 0666 | IPC_CREAT);
    
    struct msgbuf message;
    message.mtype = 1;
    strcpy(message.mtext, "Hello, this is a message!");

    msgsnd(msgid, &message, sizeof(message), 0);  // 发送消息
    
    msgrcv(msgid, &message, sizeof(message), 1, 0);  // 接收消息
    printf("Received: %s\n", message.mtext);
    
    msgctl(msgid, IPC_RMID, NULL);  // 删除消息队列
    return 0;
}

4. 共享内存(Shared Memory)

共享内存允许多个进程直接访问同一块内存区域,是进程间通信中最快的一种方式。共享内存通常需要配合其他同步机制(如信号量)来避免并发访问时的冲突。

共享内存的基本用法:
  • 使用shmget()创建共享内存段。
  • 使用shmat()将共享内存段映射到进程的地址空间。
  • 使用shmdt()解除映射,shmctl()控制共享内存的状态。
代码示例:
#include <stdio.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
    int shmid = shmget(IPC_PRIVATE, 1024, 0666 | IPC_CREAT);
    char *shmaddr = shmat(shmid, NULL, 0);

    if (fork() == 0) {  // 子进程
        sprintf(shmaddr, "Hello from child process!");
    } else {  // 父进程
        sleep(1);  // 等待子进程写入数据
        printf("Parent received: %s\n", shmaddr);
    }

    shmdt(shmaddr);  // 解除映射
    shmctl(shmid, IPC_RMID, NULL);  // 删除共享内存
    return 0;
}

5. 信号量(Semaphore)

信号量主要用于进程间同步和互斥。通过信号量可以控制多个进程对共享资源的访问,防止资源竞争和死锁的发生。

信号量的基本用法:
  • 使用semget()创建信号量集。
  • 使用semop()执行信号量操作(如P操作和V操作)。
  • 使用semctl()对信号量进行控制。
代码示例:
#include <stdio.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
    int semid = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
    
    // 初始化信号量
    semctl(semid, 0, SETVAL, 1);

    struct sembuf sem_op;
    sem_op.sem_num = 0;
    sem_op.sem_op = -1;  // P操作
    sem_op.sem_flg = 0;

    // 执行P操作
    semop(semid, &sem_op, 1);
    printf("Critical section\n");

    sem_op.sem_op = 1;  // V操作
    semop(semid, &sem_op, 1);

    semctl(semid, 0, IPC_RMID);  // 删除信号量
    return 0;
}

6. 套接字(Socket)

套接字(Socket)是一种网络通信机制,通常用于不同主机上的进程间通信。它不仅能支持本地进程间的通信,还能支持跨机器的通信。常用在客户端-服务器模型中。

套接字的基本用法:
  • 使用socket()创建套接字。
  • 使用bind()绑定地址。
  • 使用listen()accept()进行监听和接收连接。
  • 使用send()recv()进行数据传输。
总结

C语言提供了多种进程通信机制(如管道、信号、消息队列、共享内存、信号量和套接字),每种方法都有其特定的应用场景。选择合适的通信方法取决于进程间数据传递的需求、性能考虑和同步要求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值