Linux:进程间通信(共享内存详细讲解以及小项目使用和相关指令、消息队列、信号量)

简介: 通过上述讲解和代码示例,您可以理解和实现Linux系统中的进程间通信机制,包括共享内存、消息队列和信号量。这些机制在实际开发中非常重要,能够提高系统的并发处理能力和数据通信效率。希望本文能为您的学习和开发提供实用的指导和帮助。

在Linux系统中,进程间通信(IPC, Inter-Process Communication)是指多个进程之间的数据交换和同步手段。常见的IPC机制包括共享内存、消息队列和信号量。本文将详细讲解这三种IPC机制,并提供小项目示例和相关指令。

一、共享内存

共享内存是最快的IPC机制,因为它允许多个进程直接访问同一块内存区域。共享内存的使用涉及几个系统调用:shmgetshmatshmdtshmctl

1.1 创建和附加共享内存

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.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);  // 创建共享内存
    char *str = (char*) shmat(shmid, (void*)0, 0);  // 连接共享内存

    printf("Write Data: ");
    fgets(str, SHM_SIZE, stdin);

    printf("Data written in memory: %s\n", str);
    shmdt(str);  // 分离共享内存

    return 0;
}
​

1.2 读取共享内存

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

#define SHM_SIZE 1024  // 共享内存大小

int main() {
    key_t key = ftok("shmfile", 65);  // 生成唯一键值
    int shmid = shmget(key, SHM_SIZE, 0666|IPC_CREAT);  // 获取共享内存ID
    char *str = (char*) shmat(shmid, (void*)0, 0);  // 连接共享内存

    printf("Data read from memory: %s\n", str);
    shmdt(str);  // 分离共享内存
    shmctl(shmid, IPC_RMID, NULL);  // 销毁共享内存

    return 0;
}
​

1.3 相关指令

  • ipcs:显示当前系统的IPC设施状态。
  • ipcrm:删除指定的IPC对象。

二、消息队列

消息队列允许进程以消息的形式进行通信,每个消息都有一个类型标识符。消息队列的相关系统调用包括 msggetmsgsndmsgrcvmsgctl

2.1 发送消息

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

struct mesg_buffer {
    long mesg_type;
    char mesg_text[100];
} message;

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

    message.mesg_type = 1;
    printf("Write Data: ");
    fgets(message.mesg_text, 100, stdin);

    msgsnd(msgid, &message, sizeof(message), 0);  // 发送消息

    printf("Data send is : %s\n", message.mesg_text);

    return 0;
}
​

2.2 接收消息

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

struct mesg_buffer {
    long mesg_type;
    char mesg_text[100];
} message;

int main() {
    key_t key = ftok("msgfile", 65);  // 生成唯一键值
    int msgid = msgget(key, 0666 | IPC_CREAT);  // 获取消息队列ID

    msgrcv(msgid, &message, sizeof(message), 1, 0);  // 接收消息

    printf("Data Received is : %s\n", message.mesg_text);

    msgctl(msgid, IPC_RMID, NULL);  // 销毁消息队列

    return 0;
}
​

2.3 相关指令

  • ipcs -q:显示当前系统的消息队列。
  • ipcrm -q <msgid>:删除指定的消息队列。

三、信号量

信号量是用于进程同步的IPC机制。信号量的相关系统调用包括 semgetsemopsemctl

3.1 创建和初始化信号量

#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

int main() {
    key_t key = ftok("semfile", 65);  // 生成唯一键值
    int semid = semget(key, 1, 0666 | IPC_CREAT);  // 创建信号量集

    union semun sem_union;
    sem_union.val = 1;
    semctl(semid, 0, SETVAL, sem_union);  // 初始化信号量

    return 0;
}
​

3.2 P操作和V操作

#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>

void sem_op(int semid, int op) {
    struct sembuf sb;
    sb.sem_num = 0;
    sb.sem_op = op;
    sb.sem_flg = 0;
    semop(semid, &sb, 1);
}

int main() {
    key_t key = ftok("semfile", 65);  // 生成唯一键值
    int semid = semget(key, 1, 0666);  // 获取信号量ID

    printf("Waiting for semaphore...\n");
    sem_op(semid, -1);  // P操作
    printf("Enter critical section...\n");

    // 进入临界区
    sleep(5);  // 模拟临界区操作
    printf("Leaving critical section...\n");

    sem_op(semid, 1);  // V操作

    return 0;
}
​

3.3 相关指令

  • ipcs -s:显示当前系统的信号量集。
  • ipcrm -s <semid>:删除指定的信号量集。

四、小项目:生产者-消费者问题

4.1 生产者代码

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

#define SHM_SIZE 1024

void sem_op(int semid, int op) {
    struct sembuf sb;
    sb.sem_num = 0;
    sb.sem_op = op;
    sb.sem_flg = 0;
    semop(semid, &sb, 1);
}

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

    key_t sem_key = ftok("semfile", 65);
    int semid = semget(sem_key, 1, 0666 | IPC_CREAT);
    union semun sem_union;
    sem_union.val = 1;
    semctl(semid, 0, SETVAL, sem_union);

    while (1) {
        sem_op(semid, -1);
        printf("Write Data: ");
        fgets(str, SHM_SIZE, stdin);
        sem_op(semid, 1);
        sleep(1);
    }

    shmdt(str);
    shmctl(shmid, IPC_RMID, NULL);
    semctl(semid, 0, IPC_RMID);

    return 0;
}
​

4.2 消费者代码

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

#define SHM_SIZE 1024

void sem_op(int semid, int op) {
    struct sembuf sb;
    sb.sem_num = 0;
    sb.sem_op = op;
    sb.sem_flg = 0;
    semop(semid, &sb, 1);
}

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

    key_t sem_key = ftok("semfile", 65);


 int semid = semget(sem_key, 1, 0666 | IPC_CREAT);

    while (1) {
        sem_op(semid, -1);
        printf("Data read from memory: %s\n", str);
        sem_op(semid, 1);
        sleep(1);
    }

    shmdt(str);
    shmctl(shmid, IPC_RMID, NULL);
    semctl(semid, 0, IPC_RMID);

    return 0;
}
​

分析说明表

IPC机制 描述
共享内存 允许多个进程共享同一块内存,速度最快,但需要同步机制防止数据冲突。
消息队列 通过消息形式在进程间传递数据,适合异步通信,支持消息优先级。
信号量 用于进程间同步,控制对公共资源的访问,通过P操作和V操作实现。
生产者-消费者 一个典型的同步问题,通过共享内存和信号量实现生产者和消费者的协作。

思维导图

进程间通信
|
|-- 共享内存
|   |-- 创建和附加共享内存
|   |-- 读取共享内存
|   |-- 相关指令
|
|-- 消息队列
|   |-- 发送消息
|   |-- 接收消息
|   |-- 相关指令
|
|-- 信号量
|   |-- 创建和初始化信号量
|   |-- P操作和V操作
|   |-- 相关指令
|
|-- 生产者-消费者
|   |-- 生产者代码
|   |-- 消费者代码
|
|-- 分析说明表
​

通过上述讲解和代码示例,您可以理解和实现Linux系统中的进程间通信机制,包括共享内存、消息队列和信号量。这些机制在实际开发中非常重要,能够提高系统的并发处理能力和数据通信效率。希望本文能为您的学习和开发提供实用的指导和帮助。

目录
相关文章
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
421 67
|
12月前
|
Web App开发 Linux 程序员
获取和理解Linux进程以及其PID的基础知识。
总的来说,理解Linux进程及其PID需要我们明白,进程就如同汽车,负责执行任务,而PID则是独特的车牌号,为我们提供了管理的便利。知道这个,我们就可以更好地理解和操作Linux系统,甚至通过对进程的有效管理,让系统运行得更加顺畅。
344 16
|
12月前
|
Unix Linux
对于Linux的进程概念以及进程状态的理解和解析
现在,我们已经了解了Linux进程的基础知识和进程状态的理解了。这就像我们理解了城市中行人的行走和行为模式!希望这个形象的例子能帮助我们更好地理解这个重要的概念,并在实际应用中发挥作用。
237 20
|
11月前
|
监控 Shell Linux
Linux进程控制(详细讲解)
进程等待是系统通过调用特定的接口(如waitwaitpid)来实现的。来进行对子进程状态检测与回收的功能。
253 0
|
11月前
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
323 0
|
11月前
|
存储 Linux Shell
Linux进程概念-详细版(二)
在Linux进程概念-详细版(一)中我们解释了什么是进程,以及进程的各种状态,已经对进程有了一定的认识,那么这篇文章将会继续补全上篇文章剩余没有说到的,进程优先级,环境变量,程序地址空间,进程地址空间,以及调度队列。
202 0
|
11月前
|
Linux 调度 C语言
Linux进程概念-详细版(一)
子进程与父进程代码共享,其子进程直接用父进程的代码,其自己本身无代码,所以子进程无法改动代码,平时所说的修改是修改的数据。为什么要创建子进程:为了让其父子进程执行不同的代码块。子进程的数据相对于父进程是会进行写时拷贝(COW)。
262 0
|
10月前
|
存储
阿里云轻量应用服务器收费标准价格表:200Mbps带宽、CPU内存及存储配置详解
阿里云香港轻量应用服务器,200Mbps带宽,免备案,支持多IP及国际线路,月租25元起,年付享8.5折优惠,适用于网站、应用等多种场景。
3096 0
|
10月前
|
存储 缓存 NoSQL
内存管理基础:数据结构的存储方式
数据结构在内存中的存储方式主要包括连续存储、链式存储、索引存储和散列存储。连续存储如数组,数据元素按顺序连续存放,访问速度快但扩展性差;链式存储如链表,通过指针连接分散的节点,便于插入删除但访问效率低;索引存储通过索引表提高查找效率,常用于数据库系统;散列存储如哈希表,通过哈希函数实现快速存取,但需处理冲突。不同场景下应根据访问模式、数据规模和操作频率选择合适的存储结构,甚至结合多种方式以达到最优性能。掌握这些存储机制是构建高效程序和理解高级数据结构的基础。
1013 1