【操作系统】进程间的通信——消息队列

简介: 【操作系统】进程间的通信——消息队列

进程间的通信-消息队列

什么是消息队列?

  • 消息队列,用于从一个进程向另一个进程发送数据。
  • 但仅仅把数据发送到一个"队列"中,而不指定由哪个进程来接收。
  • 消息队列独立于发送消息的进程和接收消息的进程。每个消息队列都有一个标识,只有持有这个标识的进程才可以去里面拿消息。
  • 消息队列有最大长度限制:MSGMNB。
  • 消息队列中的单条消息最大长度限制:MSGMAX。

消息队列的获取

  • msgget
  • 作用:获取或创建一个消息队列
  • 函数原型: int msgget(key_t key, int msgflg);
  • 参数:

    • key:消息队列标识。
    • msgflg:访问权限。

      • IPC_CREAT——如果key不存在,则创建,类似open函数的O_CREAT。(来源详见补充1)
      • IPC_EXCL——如果key存在,则返回失败,类似open函数的O_EXCL。(来源详见补充1)
  • 返回值:

    • 成功:正整数,即消息队列标识符。
    • 失败:返回-1,并设置errno。
  • 参考补充:


消息的发送

  • msgsnd
  • 作用:发送一个消息,即把一个消息放到某一个消息队列中
  • 函数原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
  • 参数:

    • msgid:消息队列标识符。
    • msgp:消息指针。

      • 消息的类型需要自己的定义。但要求其第一个结构成员为long int。
      • 例如:
      • struct  my_msg_st {
                  long  int  msg_type;    /* 消息的类型,取>0, 接收消息时可使用该值 */
                                            /*other info */    
        } 
    • msgsz:消息的长度(不包含第一个成员msg_type)
    • msgflg:

      • IPC_NOWAIT:如果包含此选项,则消息队列满时,不发送该消息,立即返回-1。反之,如果不包含此选项,则消息队列满时,挂起本进程,直到消息队列由空间可用。
    • 返回值:

      • 成功:返回0。
      • 失败:返回-1。
    • 参考补充:


消息的接收

  • msgrcv
  • 函数原型:ssize_t msgrcv (int msqid, void *msgp, size_t msgsz, long msgtype, int msgflg);
  • 功能: 从消息队列中接收一条消息
  • 参数

    • msgid: 消息队列标识符。
    • msgp: 用于接收消息的缓存。
    • msgsz:要接收的消息长度(不包括其第一个成员)
    • msgtype: 指定接收消息的类型

      • 0:从消息队列中获取第一个消息,以实现顺序接收(先发现收)。
      • 大于0:从消息队列中获取相同类型的第一个消息。
      • 小于0:从消息队列中获取消息类型小于等于msgtype绝对值的第一个消息。
    • msgflg:

      • 如果包含 IPC_NOWAIT,则当前消息队列汇总没有指定类型的消息时,立即返回-1。
      • 如果不包含 IPC_NOWAIT,则当消息队列中没有指定类型的消息时,挂起本进程,直到收到指定类型的消息。
    • 返回值:

      • 成功:返回接收到的消息的长度(不包含第一个成员msg_type)。
      • 失败: 返回-1。

消息的控制

  • msgctl
  • 函数原型:int msgctl(int msqid, int cmd, struct msqid_ds *buf);
  • 功能:用来对消息队列的基本属性进行控制、修改
  • 参数:

    • msqid:消息队列标识符。
    • cmd: 执行的控制命令。详见补充。
    • buf:详见补充。
  • 返回值:

    • 成功:返回0。
    • 失败:返回-1。
  • 补充:


示例

  • 示例1:

    • 程序1:发送消息到消息队列,程序2进行接收。

msg_send1.c

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

#define MSG_SIZE 80

struct my_msg_st {
    long int msg_type;
    char msg[MSG_SIZE];
};

int main(void){

    int msgid;
    int ret;
    struct my_msg_st msg;

    msgid = msgget((key_t)1235, 0666|IPC_CREAT);
    if (msgid == -1) {
        printf("msgget failed!\n");
        exit(1);
    }

    msg.msg_type = 1;    
    strcpy(msg.msg, "Hello world!");//要发送的内容
    ret = msgsnd(msgid, &msg, MSG_SIZE, 0);
    if (ret == -1) {
        printf("msgsnd failed!\n");
        exit(1);
    }

    return 0;
}

msg_recv2.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

#define MSG_SIZE 80

struct my_msg_st {
    long int msg_type;
    char msg[MSG_SIZE];
};

int main(void)
{
    int msgid;
    int ret;
    struct my_msg_st msg;

    msgid = msgget((key_t)1235, 0666|IPC_CREAT);
    if (msgid == -1) {
        printf("msgget failed!\n");
        exit(1);
    }

    msg.msg_type = 0;    
    ret = msgrcv(msgid, &msg, MSG_SIZE, 0, 0);
    if (ret == -1) {
        printf("msgrcv failed!\n");
        exit(1);
    }

    printf("received: %s\n", msg.msg);

    ret = msgctl(msgid, IPC_RMID, 0);//全局性的删除-IPC_RMID
    if (ret == -1) {
        printf("msgctl(IPC_RMID) failed!\n");
        exit(1);
    }

    return 0;
}

image-20220824113543268


  • 示例2:

    • 进程1:循环等待用户输入字符串,将收到的每个字符串发送给进程2,直到用户输入exit。
    • 进程2:接收进程1发来的信息,并打印输出,直到接收到exit。

msg_send.c

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

#define MSG_SIZE 80

struct my_msg_st {
    long int msg_type;
    char msg[MSG_SIZE];
};

int main(void){
    
    int msgid;
    int ret;
    struct my_msg_st msg;

    msgid = msgget((key_t)1235, 0666|IPC_CREAT);
    if (msgid == -1) {
        printf("msgget failed!\n");
        exit(1);
    }

    while(1) {
        fgets(msg.msg, sizeof(msg.msg), stdin);
            
        msg.msg_type = 1;    
        ret = msgsnd(msgid, &msg, MSG_SIZE, 0);
        if (ret == -1) {
            printf("msgsnd failed!\n");
            exit(1);
        }

        if (strncmp(msg.msg, "exit", 4) == 0) {
            break;
        }
    }

    return 0;
}

msg_recv.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

#define MSG_SIZE 80

struct my_msg_st {
    long int msg_type;
    char msg[MSG_SIZE];
};

int main(void){
    
    int msgid;
    int ret;
    struct my_msg_st msg;

    //第二个参数为权限控制
    msgid = msgget((key_t)1235, 0666|IPC_CREAT);
    if (msgid == -1) {
        printf("msgget failed!\n");
        exit(1);
    }

    while(1) {
        msg.msg_type = 0;    
        ret = msgrcv(msgid, &msg, MSG_SIZE, 0, 0);
        if (ret == -1) {
            printf("msgrcv failed!\n");
            exit(1);
        }

        printf("received: %s\n", msg.msg);

        if (strncmp(msg.msg, "exit", 4) == 0) {
            break;
        }
    }

    ret = msgctl(msgid, IPC_RMID, 0);
    if (ret == -1) {
        printf("msgctl(IPC_RMID) failed!\n");
        exit(1);
    }

    return 0;
}

image-20220824142245709

image-20220824142253700


相关文章
|
2天前
|
存储 安全 Linux
【Linux】详解进程通信中信号量的本质&&同步和互斥的概念&&临界资源和临界区的概念
【Linux】详解进程通信中信号量的本质&&同步和互斥的概念&&临界资源和临界区的概念
|
2天前
|
Linux
【Linux】命名管道的创建方法&&基于命名管道的两个进程通信的实现
【Linux】命名管道的创建方法&&基于命名管道的两个进程通信的实现
|
2天前
|
Linux
【Linux】进程通信之匿名管道通信
【Linux】进程通信之匿名管道通信
|
2天前
|
消息中间件 存储 物联网
AMQP(Advanced Message Queuing Protocol)是一种标准化的消息队列协议,用于异步通信和消息传递
AMQP是开放标准的消息队列协议,确保异步通信中的消息路由、可靠性和灵活性。它支持持久化、确认机制,防止消息丢失,允许灵活路由与定制,适用于多领域,如企业应用、云计算和物联网。
|
2天前
|
算法 Linux 调度
深入理解操作系统:进程管理与调度策略
【5月更文挑战第10天】 本文将深入探讨操作系统的核心机制之一:进程管理。我们将从进程的概念入手,解析其生命周期,进而展开对操作系统中进程调度策略的详细讨论。文中不仅涉及理论分析,还结合了现代操作系统如Linux的实际案例,以期提供一个全面而深刻的视角。通过阅读本文,读者将对操作系统如何高效地管理计算资源有更深层次的理解。
|
5天前
|
算法 调度 UED
深入理解操作系统的进程调度策略
【5月更文挑战第7天】 在现代计算机系统中,操作系统的核心职责之一是确保CPU资源的有效分配与利用。本文旨在探讨操作系统中的进程调度策略,并分析其对系统性能的影响。我们将从调度的基本概念出发,介绍几种常见的调度算法,如先来先服务、短作业优先和轮转调度等,并对它们的优缺点进行比较。此外,文章还将讨论多级反馈队列调度策略,它结合了多种调度方法的优点,以适应不同类型的工作负载。通过深入分析,本文旨在为读者提供一个清晰的框架,以理解操作系统如何管理并发执行的多个进程,以及这些管理策略如何影响系统的整体效率和响应性。
|
7天前
|
算法 调度
深入理解操作系统:进程管理与调度策略
【5月更文挑战第5天】 在现代计算机系统中,操作系统的核心职能之一是高效地管理计算机资源,尤其是处理多个并发运行的程序(进程)。本文将探讨操作系统中的进程管理机制,重点分析不同的进程调度策略及其对系统性能的影响。我们将从理论和实践的角度出发,比较各种调度算法的优劣,并提出在特定场景下如何选择最合适的调度策略。通过深入剖析进程调度的原理和实现细节,旨在为读者提供全面而深刻的认知框架,以便于更好地理解和优化操作系统的性能。
|
8天前
|
算法 调度 云计算
深入理解操作系统:进程管理与调度策略
【5月更文挑战第4天】本文将深入探讨操作系统中的关键组成部分——进程管理,以及如何通过有效的进程调度策略提升系统性能。我们将剖析进程的概念、状态转换和控制,并详细分析不同的进程调度算法,如先来先服务(FCFS)、短作业优先(SJF)和多级反馈队列(MLFQ)。文章旨在为读者提供一个清晰的框架,以理解操作系统如何处理并发任务,保证系统资源的有效利用和响应性。
|
10天前
|
负载均衡 算法 调度
深入理解操作系统:进程管理与调度策略
【5月更文挑战第2天】 在现代计算环境中,操作系统的核心职能之一是确保系统资源的高效利用和任务的顺畅执行。本文将探讨操作系统中的关键组件——进程管理及其调度策略。通过对进程的概念、生命周期以及调度算法的详细分析,我们旨在揭示操作系统如何协调多个运行中的程序,以实现快速响应和资源优化。文章还将讨论不同类型操作系统(如实时操作系统和通用操作系统)中进程调度策略的差异性及其对系统性能的影响。通过理论与实践相结合的方式,本文为读者提供了一个全面了解操作系统进程管理的平台。
|
11天前
|
负载均衡 算法 大数据
深入理解操作系统:进程管理和调度策略
【5月更文挑战第1天】 在现代操作系统的核心功能中,进程管理与调度策略是确保系统高效、稳定运行的关键。本文旨在深入剖析操作系统中的进程概念、进程状态转换以及进程调度机制。通过对先进先出、最短作业优先和时间片轮转等调度算法的比较分析,我们不仅揭示了它们在资源分配和任务执行中的应用,还讨论了它们在不同场景下的表现和局限性。此外,文章还将探讨多核处理器环境下的调度策略演变,以及未来操作系统在进程管理方面可能面临的挑战。