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

发布于:2025-09-10 ⋅ 阅读:(23) ⋅ 点赞:(0)

简介

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

1.生产者线程
负责生成数据并将其放入共享缓冲区中。
一般来说,生产者线程会不断地生产数据,当缓冲区满时,生产者线程需要等待消费者线程消费数据,释放缓冲区空间。
2.消费者线程
负责从共享缓冲区中取出数据并进行处理。
消费者线程会不断地从缓冲区中取走数据,当缓冲区为空时,消费者线程需要等待生产者线程生产数据。


🧩 模块结构概览

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

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

#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. 编译并加载模块:

    insmod pcdev.ko
    
  2. 创建设备节点:

    mknod /dev/pcdev c <major> 0
    
  3. 用户态读写:

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

✅ 总结

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

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


网站公告

今日签到

点亮在社区的每一天
去签到