实现多进程通信的并发控制机制
消息槽设备是一种特殊的字符设备,允许多个进程向设备写入消息,而另一个进程可以读取最后一条写入的消息。这个项目重点学习Linux内核中的并发控制机制。
| 技术组件 | 功能描述 | 重要性 |
|---|---|---|
| 字符设备注册 | 创建和管理设备文件 | ⭐⭐⭐⭐⭐ |
| 互斥锁 (mutex) | 保护共享资源免受并发访问 | ⭐⭐⭐⭐⭐ |
| 等待队列 (waitqueue) | 处理阻塞和非阻塞I/O操作 | ⭐⭐⭐⭐ |
| 文件操作结构体 | 实现open, read, write等操作 | ⭐⭐⭐⭐ |
| 内存分配 | 动态管理消息存储空间 | ⭐⭐⭐ |
static const struct file_operations message_slot_fops = {
.owner = THIS_MODULE,
.open = message_slot_open,
.release = message_slot_release,
.read = message_slot_read,
.write = message_slot_write,
.llseek = no_llseek,
};
struct message_slot {
char *message; // 存储的消息
size_t message_len; // 消息长度
struct mutex lock; // 互斥锁
wait_queue_head_t readq; // 读取等待队列
int data_ready; // 数据就绪标志
};
static ssize_t message_slot_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct message_slot *slot = file->private_data;
char *new_message;
// 分配新消息空间
new_message = kmalloc(count + 1, GFP_KERNEL);
if (!new_message)
return -ENOMEM;
// 从用户空间复制数据
if (copy_from_user(new_message, buf, count)) {
kfree(new_message);
return -EFAULT;
}
new_message[count] = '\0';
// 获取互斥锁
mutex_lock(&slot->lock);
// 释放旧消息
kfree(slot->message);
// 设置新消息
slot->message = new_message;
slot->message_len = count;
slot->data_ready = 1;
// 唤醒等待的读取进程
wake_up_interruptible(&slot->readq);
// 释放互斥锁
mutex_unlock(&slot->lock);
return count;
}
在消息槽设备中,我们使用多种机制来确保并发访问的安全性:
为了验证消息槽设备的正确性,我们需要进行以下测试:
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main() {
int fd = open("/dev/message_slot", O_RDWR);
if (fd < 0) {
perror("打开设备失败");
return 1;
}
// 写入消息
char message[] = "Hello from userspace!";
write(fd, message, strlen(message));
// 读取消息
char buffer[1024];
ssize_t count = read(fd, buffer, sizeof(buffer));
if (count > 0) {
buffer[count] = '\0';
printf("读取到的消息: %s\n", buffer);
}
close(fd);
return 0;
}
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 数据竞争 | 未正确使用锁保护共享数据 | 检查所有访问共享资源的地方都使用了互斥锁 |
| 死锁 | 锁的获取和释放顺序不当 | 确保锁的获取顺序一致,避免嵌套锁 |
| 内存泄漏 | 分配的内存未正确释放 | 检查所有kmalloc都有对应的kfree |
| 用户空间数据访问错误 | 未正确使用copy_from_user/copy_to_user | 验证用户空间指针的有效性 |