c语言练习题【消息队列、共享内存、信号灯集】

练习1:消息队列

请使用消息队列实现2个终端之间互相聊天

#发送端
key_t key;
int id;

typedef struct Msgbuf{
	long channel;
	char buf[128];

}msg_t;

int main(int argc, const char *argv[])
{
	if (argc<2)
	{
		printf("传入频道号\n");
		return 1;
	}
	key=ftok("./ipc",2);
	id=msgget(key,IPC_CREAT|0666);

	int channel =atoi(argv[1]);
	msg_t msg;
	msg.channel=channel;
	while(1)
	{
		memset(msg.buf,0,128);
		printf("请输入:");
		scanf("%s",msg.buf);
		while(getchar()!=10);
		msgsnd(id,&msg,strlen(msg.buf),0);
	}

	return 0;
}
接收端
key_t key;
int id;

typedef struct Msgbuf{
	long channel;
	char buf[128];

}msg_t;

int main(int argc, const char *argv[])
{
	key=ftok("./ipc",2);
	id=msgget(key,IPC_CREAT|0666);

	int channel =0;
	msg_t msg={0};
	while(1)
	{
		memset(msg.buf,0,128);
		printf("请输入频道号:");
		scanf("%d",&channel);
		while(getchar()!=10);
		msgrcv(id,&msg,128,channel,IPC_NOWAIT);
		printf("读到的消息为:%s\n",msg.buf);
	}

	return 0;
}

练习2:共享内存 信号灯集

请使用共享内存 + 信号灯集,实现2个进程之间互相聊天

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

#define SHM_SIZE 64  // 共享内存大小
#define SEM_KEY 1234 // 信号灯集的键值

// 共享内存结构体
typedef struct shm {
    char buf[SHM_SIZE];  // 存储消息
    int ready;  // 标记是否有新消息
} shm_t;

// 信号灯集
int semid;
int shmid;
shm_t *shm_addr;

// 信号灯操作结构
struct sembuf sb;

// 获取共享内存
void* shm_alloc(int size, int proj_id) {
    key_t key = ftok("./ipc", proj_id);
    if (key == -1) {
        perror("ftok");
        return NULL;
    }

    shmid = shmget(key, size, IPC_CREAT | 0666);
    if (shmid == -1) {
        perror("shmget");
        return NULL;
    }

    shm_addr = (shm_t*)shmat(shmid, NULL, 0);
    if (shm_addr == (shm_t*)-1) {
        perror("shmat");
        return NULL;
    }
    return shm_addr;
}

// 获取信号灯集
int sem_alloc() {
    semid = semget(SEM_KEY, 2, IPC_CREAT | 0666);  // 创建信号灯集,2个信号灯
    if (semid == -1) {
        perror("semget");
        return -1;
    }

    // 初始化信号灯
    semctl(semid, 0, SETVAL, 0); // 读信号灯,初始值为 0
    semctl(semid, 1, SETVAL, 1); // 写信号灯,初始值为 1
    return 0;
}

// 信号灯操作:P操作 (阻塞)
void sem_wait(int sem_num) {
    sb.sem_num = sem_num;
    sb.sem_op = -1;  // P操作
    sb.sem_flg = 0;
    semop(semid, &sb, 1);
}

// 信号灯操作:V操作 (释放)
void sem_signal(int sem_num) {
    sb.sem_num = sem_num;
    sb.sem_op = 1;  // V操作
    sb.sem_flg = 0;
    semop(semid, &sb, 1);
}

// 信号处理函数:清理共享内存和信号灯集
void cleanup(int signum) {
    if (signum == SIGINT) {
        // 卸载共享内存
        shmdt(shm_addr);
        shmctl(shmid, IPC_RMID, NULL);

        // 删除信号灯集
        semctl(semid, 0, IPC_RMID);
        printf("Cleaned up and exiting...\n");
        exit(0);
    }
}

// 进程 1(发送消息)
void process_1() {
    char msg[SHM_SIZE];
    while (1) {
        sem_wait(1);  // 等待可以写入消息
        printf("Process 1: Enter message: ");
        fgets(msg, SHM_SIZE, stdin);
        msg[strcspn(msg, "\n")] = 0;  // 去掉末尾的换行符

        // 将消息存储到共享内存
        strncpy(shm_addr->buf, msg, SHM_SIZE);
        shm_addr->ready = 1;  // 设置 ready 标志,表示有新消息

        sem_signal(0);  // 通知进程 2 可以读取消息
    }
}

// 进程 2(接收消息)
void process_2() {
    while (1) {
        sem_wait(0);  // 等待进程 1 写入消息

        if (shm_addr->ready) {
            printf("Process 2: Received message: %s\n", shm_addr->buf);
            shm_addr->ready = 0;  // 重置 ready 标志
            sem_signal(1);  // 通知进程 1 可以继续写入消息
        }
    }
}

int main(int argc, const char *argv[]) {
    signal(SIGINT, cleanup);  // 捕获 SIGINT 信号清理资源

    if (shm_alloc(sizeof(shm_t), 1) == NULL) {
        return 1;
    }

    if (sem_alloc() == -1) {
        return 1;
    }

    // 创建子进程,进程 1 和 进程 2
    pid_t pid = fork();

    if (pid == 0) {
        // 子进程 2
        process_2();
    } else if (pid > 0) {
        // 父进程 1
        process_1();
    } else {
        perror("fork failed");
        return 1;
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值