【android 驱动开发九】生产者-消费者模型

简介

生产者 - 消费者模型是一种经典的多线程同步模型,用于处理多个线程或进程对共享资源的访问。它主要解决生产者线程和消费者线程之间的数据同步问题。

1.生产者线程

负责生成数据并将其放入共享缓冲区中。

一般来说,生产者线程会不断地生产数据,当缓冲区满时,生产者线程需要等待消费者线程消费数据,释放缓冲区空间。

2.消费者线程

负责从共享缓冲区中取出数据并进行处理。

消费者线程会不断地从缓冲区中取走数据,当缓冲区为空时,消费者线程需要等待生产者线程生产数据。


🧩 模块结构概览

  • 字符设备接口:用于用户态读写数据
  • 环形缓冲区:共享数据区,带锁保护
  • 生产者线程:周期性写入数据
  • 消费者线程:周期性读取数据
  • 同步机制 :使用 wait_queue + spinlock 实现阻塞与唤醒

🧪 内核模块代码(简化版)

c 复制代码
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/spinlock.h>

#define BUF_SIZE 128
#define DEVICE_NAME "pcdev"

static dev_t dev_num;
static struct cdev pc_cdev;

static char buffer[BUF_SIZE];
static int head = 0, tail = 0;
static spinlock_t buf_lock;
static wait_queue_head_t read_queue, write_queue;

static struct task_struct *producer_thread;
static struct task_struct *consumer_thread;

static bool data_available = false;

static int buffer_is_empty(void) { return head == tail; }
static int buffer_is_full(void) { return ((head + 1) % BUF_SIZE) == tail; }

static void buffer_write(char val) {
    buffer[head] = val;
    head = (head + 1) % BUF_SIZE;
}

static char buffer_read(void) {
    char val = buffer[tail];
    tail = (tail + 1) % BUF_SIZE;
    return val;
}

// 用户态读
static ssize_t pc_read(struct file *filp, char __user *buf, size_t count, loff_t *off) {
    char val;
    if (wait_event_interruptible(read_queue, !buffer_is_empty()))
        return -ERESTARTSYS;

    spin_lock(&buf_lock);
    val = buffer_read();
    spin_unlock(&buf_lock);

    if (copy_to_user(buf, &val, 1))
        return -EFAULT;

    wake_up_interruptible(&write_queue);
    return 1;
}

// 用户态写
static ssize_t pc_write(struct file *filp, const char __user *buf, size_t count, loff_t *off) {
    char val;
    if (copy_from_user(&val, buf, 1))
        return -EFAULT;

    if (wait_event_interruptible(write_queue, !buffer_is_full()))
        return -ERESTARTSYS;

    spin_lock(&buf_lock);
    buffer_write(val);
    spin_unlock(&buf_lock);

    wake_up_interruptible(&read_queue);
    return 1;
}

static struct file_operations pc_fops = {
    .owner = THIS_MODULE,
    .read = pc_read,
    .write = pc_write,
};

// 生产者线程
static int producer_fn(void *data) {
    char val = 'A';
    while (!kthread_should_stop()) {
        if (!buffer_is_full()) {
            spin_lock(&buf_lock);
            buffer_write(val++);
            spin_unlock(&buf_lock);
            wake_up_interruptible(&read_queue);
        }
        msleep(100);
    }
    return 0;
}

// 消费者线程
static int consumer_fn(void *data) {
    while (!kthread_should_stop()) {
        if (!buffer_is_empty()) {
            spin_lock(&buf_lock);
            char val = buffer_read();
            spin_unlock(&buf_lock);
            pr_info("Consumed: %c\n", val);
            wake_up_interruptible(&write_queue);
        }
        msleep(150);
    }
    return 0;
}

static int __init pc_init(void) {
    alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME);
    cdev_init(&pc_cdev, &pc_fops);
    cdev_add(&pc_cdev, dev_num, 1);

    spin_lock_init(&buf_lock);
    init_waitqueue_head(&read_queue);
    init_waitqueue_head(&write_queue);

    producer_thread = kthread_run(producer_fn, NULL, "producer");
    consumer_thread = kthread_run(consumer_fn, NULL, "consumer");

    pr_info("Producer-Consumer module loaded\n");
    return 0;
}

static void __exit pc_exit(void) {
    kthread_stop(producer_thread);
    kthread_stop(consumer_thread);
    cdev_del(&pc_cdev);
    unregister_chrdev_region(dev_num, 1);
    pr_info("Producer-Consumer module unloaded\n");
}

module_init(pc_init);
module_exit(pc_exit);
MODULE_LICENSE("GPL");

🧪 使用方式

  1. 编译并加载模块:

    bash 复制代码
    insmod pcdev.ko
  2. 创建设备节点:

    bash 复制代码
    mknod /dev/pcdev c <major> 0
  3. 用户态读写:

    bash 复制代码
    cat /dev/pcdev       # 读取消费者消费的数据
    echo "X" > /dev/pcdev  # 写入生产者数据

✅ 总结

这个模块展示了如何在内核中通过字符设备实现一个完整的生产者-消费者模型,支持用户态交互、内核态线程协作、同步机制和缓冲区管理。你可以扩展它支持多生产者/消费者、环形队列大小动态调整、或添加阻塞/非阻塞模式切换。

一组"生产者"线程负责生成数据并放入共享缓冲区,另一组"消费者"线程从缓冲区中取出数据进行处理。两者通过同步机制协调访问,避免竞争、空转或资源浪费。

相关推荐
xiaoshiquan120620 分钟前
as强制过滤指定依赖版本库,解决该依赖不同版本冲突
android
2501_929157682 小时前
Switch 20.5.0系统最新PSP模拟器懒人包
android·游戏·ios·pdf
用户094 小时前
Kotlin Flow的6个必知高阶技巧
android·面试·kotlin
用户094 小时前
Flutter插件与包的本质差异
android·flutter·面试
用户094 小时前
Jetpack Compose静态与动态CompositionLocal深度解析
android·面试·kotlin
聆风吟º7 小时前
【Spring Boot 报错已解决】别让端口配置卡壳!Spring Boot “Binding to target failed” 报错解决思路
android·java·spring boot
非专业程序员Ping14 小时前
HarfBuzz概览
android·ios·swift·font
DeeplyMind15 小时前
AMD rocr-libhsakmt分析系列3-4:svm-reserve模式实现分析
linux·驱动开发·1024程序员节·amdgpu·kfd·rocr
Jeled15 小时前
「高级 Android 架构师成长路线」的第 1 阶段 —— 强化体系与架构思维(Clean Architecture 实战)
android·kotlin·android studio·1024程序员节
明道源码17 小时前
Kotlin 控制流、函数、Lambda、高阶函数
android·开发语言·kotlin