linux学习:进程通信 消息队列 共享内存

目录

例子1  消息队列的创建、消息的接收、发送和队列的删除

例子2  创建消息队列,发送一条消息,接收回应消息

例子3    父进程等待子进程释放信号量才继续运行,同步

例子4    共享内存  创建共享内存段、附加到该内存、打印存储的数据,并最后分离共享内存

例子5    创建和管理共享内存,包括写入数据、等待一段时间(用于模拟数据被其他进程读取或使用的情况),最后清理共享内存资源


例子1  消息队列的创建、消息的接收、发送和队列的删除

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h> // 包含字符串处理函数库

// 定义消息结构体,用于消息队列通信
struct msgbuf {
	long mtype;       /* 消息类型, 必须大于 0 */
    char mtext[256];  /* 消息数据 */
};

int main()
{
	// 用于读取消息的结构体
	struct msgbuf readBuf;	

	key_t key;
	// 生成IPC键值,使用当前目录下的文件'.'和字符'm'作为输入
	key = ftok(".", 'm');
	printf("key=%x\n", key);  // 打印生成的键值,用于调试

	// 创建或获取消息队列,权限设置为0777,允许任何用户读写
	int msgId = msgget(key, IPC_CREAT | 0777);
	if(msgId == -1 ){
		printf("get queue failure\n");  // 如果消息队列创建或获取失败,输出错误消息
		return -1;  // 出错退出
	}

	// 清空读取缓冲区
	memset(&readBuf, 0, sizeof(struct msgbuf));

	// 从消息队列接收类型为888的消息,不使用任何特殊选项
	msgrcv(msgId, &readBuf, sizeof(readBuf.mtext), 888, 0);	
	printf("read from queue: %s\n", readBuf.mtext);  // 打印接收到的消息内容

    // 设置发送消息的结构体,消息类型为988,内容为"thank you for reach"
    struct msgbuf sendBuf = {988, "thank you for reach"};
    // 发送消息到消息队列
    msgsnd(msgId, &sendBuf, strlen(sendBuf.mtext), 0);

	// 删除消息队列
	msgctl(msgId, IPC_RMID, NULL);

	return 0;
}

例子2  创建消息队列,发送一条消息,接收回应消息

#include <stdio.h>      // 包含标准输入输出函数库
#include <sys/types.h>  // 包含系统数据类型定义
#include <sys/ipc.h>    // 包含IPC(进程间通信)相关的头文件
#include <sys/msg.h>    // 包含消息队列相关的函数声明和数据结构
#include <string.h>     // 包含字符串处理函数库

// 定义消息结构体,用于消息队列通信
struct msgbuf {
    long mtype;         /* 消息类型, 必须大于 0 */
    char mtext[256];    /* 消息数据 */
};

int main()
{
    struct msgbuf sendBuf = {888, "this is message from queue"};  // 发送消息的结构体
    struct msgbuf readBuf;  // 读取消息的结构体

    // 初始化读取缓冲区
    memset(&readBuf, 0, sizeof(struct msgbuf));

    // 生成IPC键值,使用当前目录下的文件'.'和字符'm'作为输入
    key_t key = ftok(".", 'm');
    printf("key=%x\n", key);  // 打印生成的键值,用于调试

    // 创建或获取消息队列,权限设置为0777,允许任何用户读写
    int msgId = msgget(key, IPC_CREAT | 0777);
    if(msgId == -1) {
        printf("get queue failure\n");
        return -1;  // 如果消息队列创建或获取失败,输出错误消息并退出程序
    }

    // 向消息队列发送消息
    msgsnd(msgId, &sendBuf, strlen(sendBuf.mtext), 0);  // 不使用任何特殊选项
    printf("send over\n");

    // 从消息队列接收类型为988的消息,不使用任何特殊选项
    msgrcv(msgId, &readBuf, sizeof(readBuf.mtext), 988, 0);
    printf("return from get: %s\n", readBuf.mtext);  // 打印接收到的消息内容

    // 删除消息队列
    msgctl(msgId, IPC_RMID, NULL);

    return 0;  // 程序正常结束
}

例子3    父进程等待子进程释放信号量才继续运行,同步

#include <stdio.h>   // 包含标准输入输出函数库
#include <sys/types.h>  // 包含系统数据类型定义
#include <sys/ipc.h>    // 包含IPC(进程间通信)相关的头文件
#include <sys/sem.h>    // 包含System V信号量相关的函数声明和数据结构

// 为semctl定义的union,用于设置信号量的值
union semun {
    int              val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                (Linux-specific) */
};

// P操作函数:尝试获取信号量
void pGetKey(int id)
{
    struct sembuf set;

    set.sem_num = 0;       // 信号量编号
    set.sem_op = -1;       // 操作类型为减1,表示获取信号量
    set.sem_flg = SEM_UNDO;  // 在进程终止时撤销操作

    semop(id, &set, 1);    // 执行操作
    printf("get key\n");   // 打印获取信号量的信息
}

// V操作函数:释放信号量
void vPutBackKey(int id)
{
    struct sembuf set;

    set.sem_num = 0;       // 信号量编号
    set.sem_op = 1;        // 操作类型为加1,表示释放信号量
    set.sem_flg = SEM_UNDO;  // 在进程终止时撤销操作

    semop(id, &set, 1);    // 执行操作
    printf("put back the key\n");   // 打印释放信号量的信息
}

int main(int argc, char const *argv[])
{
    key_t key;
    int semid;

    key = ftok(".", 2);  // 生成IPC键值
    semid = semget(key, 1, IPC_CREAT | 0666);  // 获取或创建一个信号量

    union semun initsem;
    initsem.val = 0;
    semctl(semid, 0, SETVAL, initsem);  // 初始化信号量的值为0

    int pid = fork();  // 创建子进程
    if(pid > 0){
        // 父进程
        pGetKey(semid);  // 获取信号量
        printf("this is father\n");
        vPutBackKey(semid);  // 释放信号量
        semctl(semid, 0, IPC_RMID, NULL);  // 删除信号量
    }
    else if(pid == 0){
        // 子进程
        printf("this is child\n");
        vPutBackKey(semid);  // 释放信号量
    }else{
        // fork失败
        printf("fork error\n");
    }            

    return 0;
}

例子4    共享内存  创建共享内存段、附加到该内存、打印存储的数据,并最后分离共享内存

#include <sys/ipc.h>   // 包含IPC标准头文件,用于键值的生成等
#include <sys/shm.h>   // 包含System V共享内存功能相关的头文件
#include <stdlib.h>    // 包含标准库函数,如exit
#include <stdio.h>     // 包含标准输入输出函数
#include <string.h>    // 包含字符串处理函数

int main()
{
    int shmid;  // 共享内存标识符
    char *shmaddr;  // 指向共享内存的指针

    key_t key;  // IPC键
    key = ftok(".", 1);  // 使用ftok生成一个唯一键值,当前目录作为路径,1作为项目标识符
    
    // 请求访问键值为key的共享内存,大小为4096字节(1024*4),权限标志为0(只获取不创建)
    shmid = shmget(key, 1024 * 4, 0);
    if (shmid == -1) {
        printf("shmget noOk\n");  // 如果获取共享内存失败,打印错误消息
        exit(-1);  // 退出程序
    }

    // 将共享内存附加到进程的地址空间
    shmaddr = shmat(shmid, 0, 0);  // 第二个参数是指定内存附加到进程空间的地址(0表示系统选择)
    if (shmaddr == (void*) -1) {
        printf("shmat error\n");  // 附加失败
        exit(-1);
    }

    printf("shmat ok\n");  // 打印附加成功消息
    printf("data: %s\n", shmaddr);  // 打印共享内存中的数据

    // 将共享内存从当前进程的地址空间分离
    shmdt(shmaddr);

    printf("quit\n");  // 打印退出消息
    
    return 0;  // 正常退出程序
}

例子5    创建和管理共享内存,包括写入数据、等待一段时间(用于模拟数据被其他进程读取或使用的情况),最后清理共享内存资源

#include <sys/ipc.h>   // 包含IPC标准头文件,用于键值的生成等
#include <sys/shm.h>   // 包含System V共享内存功能相关的头文件
#include <stdlib.h>    // 包含标准库函数,如exit
#include <stdio.h>     // 包含标准输入输出函数
#include <string.h>    // 包含字符串处理函数
#include <unistd.h>    // 包含常用的系统调用函数,如sleep

int main()
{
    int shmid;  // 共享内存标识符
    char *shmaddr;  // 指向共享内存的指针

    key_t key;  // IPC键
    key = ftok(".", 1);  // 使用ftok生成一个唯一键值,当前目录作为路径,1作为项目标识符
    
    // 创建共享内存,大小为4KB,权限设置为0666,并设置IPC_CREAT标志以确保如果不存在则创建
    shmid = shmget(key, 1024 * 4, IPC_CREAT | 0666);
    if (shmid == -1) {
        printf("shmget noOk\n");  // 如果获取共享内存失败,打印错误消息
        exit(-1);  // 退出程序
    }

    // 将共享内存附加到进程的地址空间
    shmaddr = shmat(shmid, 0, 0);  // 第二个参数是指定内存附加到进程空间的地址(0表示系统选择)
    if (shmaddr == (void *) -1) {
        printf("shmat error\n");  // 附加失败
        exit(-1);
    }
    printf("shmat ok\n");  // 打印附加成功消息

    // 将字符串 "chenlichen" 复制到共享内存中
    strcpy(shmaddr, "helloworld");

    // 休眠5秒,模拟等待其他进程/线程读取或操作这段共享内存
    sleep(5);

    // 将共享内存从当前进程的地址空间分离
    shmdt(shmaddr);

    // 删除共享内存段
    shmctl(shmid, IPC_RMID, 0);

    printf("quit\n");  // 打印退出消息
    
    return 0;  // 程序正常结束
}

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值