车辆TBOX科普 第45次

一、多线程编程深入解析

1.1 多线程基础概念

1.1.1 线程与进程的区别

在深入多线程编程之前,必须清楚理解线程和进程的本质区别:

  • 进程:资源分配的基本单位,拥有独立的地址空间、文件描述符、环境变量等
  • 线程:CPU调度的基本单位,共享进程的资源,但拥有独立的栈空间和寄存器状态

关键特性对比

c 复制代码
// 进程间通信 vs 线程间通信
进程间通信:管道、消息队列、共享内存、信号量
线程间通信:全局变量、互斥锁、条件变量、线程信号
1.1.2 多线程的优势与挑战

优势

  • 提高程序响应性
  • 更好的资源利用率
  • 简化异步事件处理
  • 改善程序结构

挑战

  • 数据竞争和竞态条件
  • 死锁和活锁
  • 优先级反转
  • 调试复杂度增加

1.2 POSIX线程编程

1.2.1 线程创建与管理
c 复制代码
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

// 线程函数原型
void *thread_function(void *arg);

// 线程属性设置示例
void create_thread_with_attributes() {
    pthread_t thread_id;
    pthread_attr_t attr;
    int ret;
    
    // 初始化线程属性
    pthread_attr_init(&attr);
    
    // 设置线程为分离状态
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    
    // 设置线程栈大小(1MB)
    size_t stack_size = 1024 * 1024;
    pthread_attr_setstacksize(&attr, stack_size);
    
    // 设置调度策略
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
    
    // 创建线程
    ret = pthread_create(&thread_id, &attr, thread_function, NULL);
    if (ret != 0) {
        perror("pthread_create failed");
        return;
    }
    
    // 销毁属性对象
    pthread_attr_destroy(&attr);
}

// 基本的线程创建
void basic_thread_creation() {
    pthread_t threads[5];
    int thread_args[5];
    int i, ret;
    
    for (i = 0; i < 5; i++) {
        thread_args[i] = i;
        ret = pthread_create(&threads[i], NULL, thread_function, &thread_args[i]);
        if (ret != 0) {
            perror("pthread_create failed");
            continue;
        }
    }
    
    // 等待所有线程完成
    for (i = 0; i < 5; i++) {
        pthread_join(threads[i], NULL);
    }
}

void *thread_function(void *arg) {
    int thread_num = *(int *)arg;
    printf("线程 %d 开始执行,线程ID: %lu\n", 
           thread_num, (unsigned long)pthread_self());
    
    // 模拟工作负载
    for (int i = 0; i < 3; i++) {
        printf("线程 %d 正在工作...\n", thread_num);
        sleep(1);
    }
    
    printf("线程 %d 执行完成\n", thread_num);
    return NULL;
}
1.2.2 线程同步机制
互斥锁(Mutex)
c 复制代码
#include <pthread.h>

// 共享资源
struct shared_data {
    int counter;
    pthread_mutex_t mutex;
};

// 初始化共享数据
void init_shared_data(struct shared_data *data) {
    data->counter = 0;
    pthread_mutex_init(&data->mutex, NULL);
}

// 线程安全的计数器递增
void safe_increment(struct shared_data *data) {
    pthread_mutex_lock(&data->mutex);
    data->counter++;
    printf("计数器值: %d (线程: %lu)\n", 
           data->counter, (unsigned long)pthread_self());
    pthread_mutex_unlock(&data->mutex);
}

// 递归互斥锁示例
void recursive_mutex_example() {
    pthread_mutex_t mutex;
    pthread_mutexattr_t attr;
    
    // 初始化互斥锁属性
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    
    // 初始化递归互斥锁
    pthread_mutex_init(&mutex, &attr);
    
    // 递归加锁
    pthread_mutex_lock(&mutex);
    pthread_mutex_lock(&mutex);  // 不会死锁
    
    // 工作代码...
    
    pthread_mutex_unlock(&mutex);
    pthread_mutex_unlock(&mutex);
    
    pthread_mutex_destroy(&mutex);
    pthread_mutexattr_destroy(&attr);
}
读写锁(Read-Write Lock)
c 复制代码
#include <pthread.h>

// 读写锁保护的数据结构
struct rw_data {
    int value;
    pthread_rwlock_t rwlock;
};

void init_rw_data(struct rw_data *data) {
    data->value = 0;
    pthread_rwlock_init(&data->rwlock, NULL);
}

// 读者线程
void *reader_thread(void *arg) {
    struct rw_data *data = (struct rw_data *)arg;
    
    for (int i = 0; i < 5; i++) {
        pthread_rwlock_rdlock(&data->rwlock);
        printf("读者 %lu 读取值: %d\n", 
               (unsigned long)pthread_self(), data->value);
        pthread_rwlock_unlock(&data->rwlock);
        usleep(100000); // 100ms
    }
    return NULL;
}

// 写者线程
void *writer_thread(void *arg) {
    struct rw_data *data = (struct rw_data *)arg;
    
    for (int i = 0; i < 3; i++) {
        pthread_rwlock_wrlock(&data->rwlock);
        data->value++;
        printf("写者 %lu 更新值: %d\n", 
               (unsigned long)pthread_self(), data->value);
        pthread_rwlock_unlock(&data->rwlock);
        usleep(200000); // 200ms
    }
    return NULL;
}
条件变量(Condition Variable)
c 复制代码
#include <pthread.h>

// 生产者-消费者示例
struct buffer {
    int data[10];
    int count;
    int in;
    int out;
    pthread_mutex_t mutex;
    pthread_cond_t not_empty;
    pthread_cond_t not_full;
};

void init_buffer(struct buffer *buf) {
    buf->count = 0;
    buf->in = 0;
    buf->out = 0;
    pthread_mutex_init(&buf->mutex, NULL);
    pthread_cond_init(&buf->not_empty, NULL);
    pthread_cond_init(&buf->not_full, NULL);
}

// 生产者
void *producer(void *arg) {
    struct buffer *buf = (struct buffer *)arg;
    
    for (int i = 0; i < 20; i++) {
        pthread_mutex_lock(&buf->mutex);
        
        // 等待缓冲区不满
        while (buf->count == 10) {
            pthread_cond_wait(&buf->not_full, &buf->mutex);
        }
        
        // 生产数据
        buf->data[buf->in] = i;
        buf->in = (buf->in + 1) % 10;
        buf->count++;
        
        printf("生产者 %lu 生产: %d\n", 
               (unsigned long)pthread_self(), i);
        
        // 通知消费者
        pthread_cond_signal(&buf->not_empty);
        pthread_mutex_unlock(&buf->mutex);
        
        usleep(50000); // 50ms
    }
    return NULL;
}

// 消费者
void *consumer(void *arg) {
    struct buffer *buf = (struct buffer *)arg;
    
    for (int i = 0; i < 20; i++) {
        pthread_mutex_lock(&buf->mutex);
        
        // 等待缓冲区不空
        while (buf->count == 0) {
            pthread_cond_wait(&buf->not_empty, &buf->mutex);
        }
        
        // 消费数据
        int item = buf->data[buf->out];
        buf->out = (buf->out + 1) % 10;
        buf->count--;
        
        printf("消费者 %lu 消费: %d\n", 
               (unsigned long)pthread_self(), item);
        
        // 通知生产者
        pthread_cond_signal(&buf->not_full);
        pthread_mutex_unlock(&buf->mutex);
        
        usleep(100000); // 100ms
    }
    return NULL;
}
1.2.3 线程池实现
c 复制代码
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

// 任务结构
struct task {
    void (*function)(void *);
    void *argument;
    struct task *next;
};

// 线程池结构
struct thread_pool {
    pthread_mutex_t lock;
    pthread_cond_t notify;
    pthread_t *threads;
    struct task *task_queue;
    int thread_count;
    int queue_size;
    int count;
    int shutdown;
    int started;
};

// 工作线程函数
void *worker_thread(void *thread_pool) {
    struct thread_pool *pool = (struct thread_pool *)thread_pool;
    struct task *task;
    
    while (1) {
        pthread_mutex_lock(&pool->lock);
        
        // 等待任务或关闭信号
        while ((pool->count == 0) && (!pool->shutdown)) {
            pthread_cond_wait(&pool->notify, &pool->lock);
        }
        
        // 检查是否需要关闭
        if (pool->shutdown && (pool->count == 0)) {
            break;
        }
        
        // 获取任务
        task = pool->task_queue;
        if (task == NULL) {
            pthread_mutex_unlock(&pool->lock);
            continue;
        }
        
        // 从队列中移除任务
        pool->task_queue = task->next;
        pool->count--;
        
        pthread_mutex_unlock(&pool->lock);
        
        // 执行任务
        (*(task->function))(task->argument);
        free(task);
    }
    
    pool->started--;
    pthread_mutex_unlock(&pool->lock);
    pthread_exit(NULL);
    return NULL;
}

// 创建线程池
struct thread_pool *thread_pool_create(int thread_count, int queue_size) {
    struct thread_pool *pool;
    int i;
    
    if (thread_count <= 0 || queue_size <= 0) {
        return NULL;
    }
    
    pool = (struct thread_pool *)malloc(sizeof(struct thread_pool));
    if (pool == NULL) {
        return NULL;
    }
    
    // 初始化
    pool->thread_count = 0;
    pool->queue_size = queue_size;
    pool->count = 0;
    pool->shutdown = 0;
    pool->started = 0;
    pool->task_queue = NULL;
    
    // 分配线程数组
    pool->threads = (pthread_t *)malloc(sizeof(pthread_t) * thread_count);
    if (pool->threads == NULL) {
        free(pool);
        return NULL;
    }
    
    // 初始化互斥锁和条件变量
    if (pthread_mutex_init(&(pool->lock), NULL) != 0 ||
        pthread_cond_init(&(pool->notify), NULL) != 0) {
        free(pool->threads);
        free(pool);
        return NULL;
    }
    
    // 创建工作线程
    for (i = 0; i < thread_count; i++) {
        if (pthread_create(&(pool->threads[i]), NULL, 
                          worker_thread, (void *)pool) == 0) {
            pool->thread_count++;
            pool->started++;
        }
    }
    
    // 如果所有线程创建失败
    if (pool->thread_count == 0) {
        free(pool->threads);
        free(pool);
        return NULL;
    }
    
    return pool;
}

// 向线程池添加任务
int thread_pool_add(struct thread_pool *pool, void (*function)(void *), 
                   void *argument) {
    int err = 0;
    
    if (pool == NULL || function == NULL) {
        return -1;
    }
    
    if (pthread_mutex_lock(&(pool->lock)) != 0) {
        return -1;
    }
    
    // 检查队列是否已满
    if (pool->count == pool->queue_size) {
        err = -2; // 队列满
        goto done;
    }
    
    // 检查是否已关闭
    if (pool->shutdown) {
        err = -3; // 已关闭
        goto done;
    }
    
    // 创建新任务
    struct task *task = (struct task *)malloc(sizeof(struct task));
    if (task == NULL) {
        err = -4; // 内存不足
        goto done;
    }
    
    task->function = function;
    task->argument = argument;
    task->next = NULL;
    
    // 添加到队列
    if (pool->task_queue == NULL) {
        pool->task_queue = task;
    } else {
        struct task *current = pool->task_queue;
        while (current->next != NULL) {
            current = current->next;
        }
        current->next = task;
    }
    
    pool->count++;
    
    // 通知工作线程
    if (pthread_cond_signal(&(pool->notify)) != 0) {
        err = -5;
    }

done:
    pthread_mutex_unlock(&pool->lock);
    return err;
}

1.3 高级多线程技术

1.3.1 线程局部存储
c 复制代码
#include <pthread.h>

// 线程局部存储示例
static pthread_key_t thread_log_key;

void write_to_thread_log(const char *message) {
    FILE *thread_log = (FILE *)pthread_getspecific(thread_log_key);
    fprintf(thread_log, "%s\n", message);
}

void close_thread_log(void *thread_log) {
    fclose((FILE *)thread_log);
}

void *thread_function_tls(void *arg) {
    char thread_log_filename[256];
    FILE *thread_log;
    
    // 创建线程特定的日志文件名
    sprintf(thread_log_filename, "thread_%lu.log", (unsigned long)pthread_self());
    
    // 打开日志文件
    thread_log = fopen(thread_log_filename, "w");
    
    // 设置线程局部存储
    pthread_setspecific(thread_log_key, thread_log);
    
    write_to_thread_log("线程开始");
    
    // 执行工作...
    for (int i = 0; i < 5; i++) {
        write_to_thread_log("处理中...");
    }
    
    write_to_thread_log("线程结束");
    return NULL;
}

void init_thread_logging() {
    pthread_key_create(&thread_log_key, close_thread_log);
}
1.3.2 线程取消与清理
c 复制代码
#include <pthread.h>

// 线程清理处理程序
void cleanup_handler(void *arg) {
    printf("清理资源: %s\n", (char *)arg);
    // 释放资源,如关闭文件、释放锁等
}

void *cancellable_thread(void *arg) {
    // 注册清理处理程序
    pthread_cleanup_push(cleanup_handler, "资源1");
    pthread_cleanup_push(cleanup_handler, "资源2");
    
    // 设置取消类型为延迟取消
    int old_type;
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_type);
    
    // 设置取消点
    pthread_testcancel();
    
    // 执行工作
    for (int i = 0; i < 10; i++) {
        printf("工作循环 %d\n", i);
        sleep(1);
        
        // 定期检查取消请求
        pthread_testcancel();
    }
    
    // 弹出清理处理程序(不执行,因为线程正常完成)
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);
    
    return NULL;
}

二、Linux驱动开发基础

2.1 Linux驱动架构概述

2.1.1 驱动分类

Linux内核支持多种类型的设备驱动:

  • 字符设备:以字节流方式访问的设备,如键盘、鼠标
  • 块设备:以数据块方式访问的设备,如硬盘、U盘
  • 网络设备:网络接口设备,如网卡
  • 杂项设备:不适合上述分类的设备
2.1.2 内核模块基础
c 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

// 模块信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A Simple Linux Driver");
MODULE_VERSION("1.0");

// 模块初始化函数
static int __init hello_init(void) {
    printk(KERN_INFO "Hello, World! Driver loaded.\n");
    return 0;
}

// 模块清理函数
static void __exit hello_exit(void) {
    printk(KERN_INFO "Goodbye, World! Driver unloaded.\n");
}

// 注册初始化和清理函数
module_init(hello_init);
module_exit(hello_exit);

对应的Makefile:

makefile 复制代码
obj-m += hello.o

KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean

2.2 字符设备驱动开发

2.2.1 字符设备注册
c 复制代码
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>

#define DEVICE_NAME "mydevice"
#define CLASS_NAME "myclass"

static int major_number;
static struct class *myclass = NULL;
static struct cdev my_cdev;

// 文件操作函数
static int device_open(struct inode *inodep, struct file *filep) {
    printk(KERN_INFO "设备被打开\n");
    return 0;
}

static int device_release(struct inode *inodep, struct file *filep) {
    printk(KERN_INFO "设备被关闭\n");
    return 0;
}

static ssize_t device_read(struct file *filep, char *buffer, 
                          size_t len, loff_t *offset) {
    printk(KERN_INFO "设备读取操作\n");
    return 0;
}

static ssize_t device_write(struct file *filep, const char *buffer,
                           size_t len, loff_t *offset) {
    printk(KERN_INFO "设备写入操作\n");
    return len;
}

// 文件操作结构
static struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = device_open,
    .release = device_release,
    .read = device_read,
    .write = device_write,
};

// 设备初始化
static int __init char_device_init(void) {
    int ret;
    dev_t dev_num;
    
    // 动态分配主设备号
    ret = alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME);
    if (ret < 0) {
        printk(KERN_ALERT "无法分配设备号\n");
        return ret;
    }
    
    major_number = MAJOR(dev_num);
    printk(KERN_INFO "分配的设备号: %d\n", major_number);
    
    // 初始化cdev结构
    cdev_init(&my_cdev, &fops);
    my_cdev.owner = THIS_MODULE;
    
    // 添加cdev到系统
    ret = cdev_add(&my_cdev, dev_num, 1);
    if (ret < 0) {
        unregister_chrdev_region(dev_num, 1);
        printk(KERN_ALERT "无法添加cdev\n");
        return ret;
    }
    
    // 创建设备类
    myclass = class_create(THIS_MODULE, CLASS_NAME);
    if (IS_ERR(myclass)) {
        cdev_del(&my_cdev);
        unregister_chrdev_region(dev_num, 1);
        return PTR_ERR(myclass);
    }
    
    // 创建设备文件
    device_create(myclass, NULL, dev_num, NULL, DEVICE_NAME);
    
    printk(KERN_INFO "字符设备驱动加载成功\n");
    return 0;
}

// 设备清理
static void __exit char_device_exit(void) {
    dev_t dev_num = MKDEV(major_number, 0);
    
    // 销毁设备文件
    device_destroy(myclass, dev_num);
    
    // 销毁设备类
    class_destroy(myclass);
    
    // 删除cdev
    cdev_del(&my_cdev);
    
    // 释放设备号
    unregister_chrdev_region(dev_num, 1);
    
    printk(KERN_INFO "字符设备驱动卸载成功\n");
}

module_init(char_device_init);
module_exit(char_device_exit);
2.2.2 高级字符设备操作
c 复制代码
#include <linux/ioctl.h>
#include <linux/uaccess.h>

// 定义ioctl命令
#define MYDEVICE_IOCTL_MAGIC 'k'
#define MYDEVICE_IOCTL_RESET _IO(MYDEVICE_IOCTL_MAGIC, 0)
#define MYDEVICE_IOCTL_SET_VALUE _IOW(MYDEVICE_IOCTL_MAGIC, 1, int)
#define MYDEVICE_IOCTL_GET_VALUE _IOR(MYDEVICE_IOCTL_MAGIC, 2, int)

// 设备私有数据结构
struct mydevice_data {
    int value;
    struct mutex lock;
};

static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
    struct mydevice_data *data = file->private_data;
    int ret = 0;
    int tmp;
    
    // 检查命令类型
    if (_IOC_TYPE(cmd) != MYDEVICE_IOCTL_MAGIC) {
        return -ENOTTY;
    }
    
    switch (cmd) {
    case MYDEVICE_IOCTL_RESET:
        mutex_lock(&data->lock);
        data->value = 0;
        mutex_unlock(&data->lock);
        printk(KERN_INFO "设备重置\n");
        break;
        
    case MYDEVICE_IOCTL_SET_VALUE:
        if (copy_from_user(&tmp, (int __user *)arg, sizeof(tmp))) {
            return -EFAULT;
        }
        mutex_lock(&data->lock);
        data->value = tmp;
        mutex_unlock(&data->lock);
        printk(KERN_INFO "设置值: %d\n", tmp);
        break;
        
    case MYDEVICE_IOCTL_GET_VALUE:
        mutex_lock(&data->lock);
        tmp = data->value;
        mutex_unlock(&data->lock);
        if (copy_to_user((int __user *)arg, &tmp, sizeof(tmp))) {
            return -EFAULT;
        }
        printk(KERN_INFO "获取值: %d\n", tmp);
        break;
        
    default:
        return -ENOTTY;
    }
    
    return ret;
}

// 更新文件操作结构
static struct file_operations fops_advanced = {
    .owner = THIS_MODULE,
    .open = device_open,
    .release = device_release,
    .read = device_read,
    .write = device_write,
    .unlocked_ioctl = device_ioctl,
};

2.3 平台设备驱动

2.3.1 设备树使用

设备树(Device Tree)是现代Linux驱动开发中硬件描述的标准方式:

c 复制代码
// 设备树节点示例
mydevice@10000000 {
    compatible = "vendor,mydevice";
    reg = <0x10000000 0x1000>;
    interrupts = <0 25 4>;
    clock-frequency = <50000000>;
    status = "okay";
};

// 驱动中的设备树匹配
static const struct of_device_id mydevice_of_match[] = {
    { .compatible = "vendor,mydevice" },
    { }
};
MODULE_DEVICE_TABLE(of, mydevice_of_match);

// 平台驱动结构
static struct platform_driver mydevice_driver = {
    .probe = mydevice_probe,
    .remove = mydevice_remove,
    .driver = {
        .name = "mydevice",
        .of_match_table = mydevice_of_match,
        .owner = THIS_MODULE,
    },
};

// 探测函数
static int mydevice_probe(struct platform_device *pdev) {
    struct device *dev = &pdev->dev;
    struct mydevice_data *data;
    struct resource *res;
    int irq;
    int ret;
    
    // 分配设备数据
    data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
    if (!data) {
        return -ENOMEM;
    }
    
    // 获取内存资源
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (!res) {
        dev_err(dev, "无法获取内存资源\n");
        return -ENODEV;
    }
    
    // 获取中断号
    irq = platform_get_irq(pdev, 0);
    if (irq < 0) {
        dev_err(dev, "无法获取中断号\n");
        return irq;
    }
    
    // 初始化互斥锁
    mutex_init(&data->lock);
    
    // 设置设备私有数据
    platform_set_drvdata(pdev, data);
    
    dev_info(dev, "设备探测成功\n");
    return 0;
}
2.3.2 中断处理
c 复制代码
#include <linux/interrupt.h>

// 中断处理函数
static irqreturn_t mydevice_interrupt(int irq, void *dev_id) {
    struct mydevice_data *data = dev_id;
    
    // 处理中断
    // ...
    
    // 确认中断处理完成
    return IRQ_HANDLED;
}

// 在probe函数中注册中断
static int mydevice_probe_with_irq(struct platform_device *pdev) {
    // ... 其他初始化代码
    
    // 注册中断处理程序
    ret = devm_request_irq(dev, irq, mydevice_interrupt,
                          IRQF_SHARED, "mydevice", data);
    if (ret) {
        dev_err(dev, "无法注册中断处理程序\n");
        return ret;
    }
    
    return 0;
}

2.4 完整的驱动示例

下面是一个完整的虚拟字符设备驱动示例,集成了前面讨论的各种技术:

c 复制代码
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/mutex.h>
#include <linux/slab.h>

#define DEVICE_NAME "complete_device"
#define CLASS_NAME "completeclass"
#define BUFFER_SIZE 1024

// 设备数据结构
struct complete_device_data {
    struct cdev cdev;
    struct mutex lock;
    char buffer[BUFFER_SIZE];
    size_t buffer_len;
};

static int major_number;
static struct class *device_class = NULL;
static struct complete_device_data *device_data = NULL;

// 文件操作函数
static int complete_device_open(struct inode *inodep, struct file *filep) {
    struct complete_device_data *data;
    
    data = container_of(inodep->i_cdev, struct complete_device_data, cdev);
    filep->private_data = data;
    
    printk(KERN_INFO "设备打开\n");
    return 0;
}

static int complete_device_release(struct inode *inodep, struct file *filep) {
    printk(KERN_INFO "设备关闭\n");
    return 0;
}

static ssize_t complete_device_read(struct file *filep, char __user *buffer,
                                   size_t len, loff_t *offset) {
    struct complete_device_data *data = filep->private_data;
    ssize_t bytes_to_read;
    int ret;
    
    if (mutex_lock_interruptible(&data->lock)) {
        return -ERESTARTSYS;
    }
    
    bytes_to_read = min(len, data->buffer_len - *offset);
    if (bytes_to_read <= 0) {
        mutex_unlock(&data->lock);
        return 0;
    }
    
    ret = copy_to_user(buffer, data->buffer + *offset, bytes_to_read);
    if (ret) {
        mutex_unlock(&data->lock);
        return -EFAULT;
    }
    
    *offset += bytes_to_read;
    mutex_unlock(&data->lock);
    
    return bytes_to_read;
}

static ssize_t complete_device_write(struct file *filep, const char __user *buffer,
                                    size_t len, loff_t *offset) {
    struct complete_device_data *data = filep->private_data;
    ssize_t bytes_to_write;
    int ret;
    
    if (mutex_lock_interruptible(&data->lock)) {
        return -ERESTARTSYS;
    }
    
    bytes_to_write = min(len, BUFFER_SIZE - *offset);
    if (bytes_to_write <= 0) {
        mutex_unlock(&data->lock);
        return -ENOSPC;
    }
    
    ret = copy_from_user(data->buffer + *offset, buffer, bytes_to_write);
    if (ret) {
        mutex_unlock(&data->lock);
        return -EFAULT;
    }
    
    *offset += bytes_to_write;
    data->buffer_len = max(data->buffer_len, *offset);
    mutex_unlock(&data->lock);
    
    return bytes_to_write;
}

static struct file_operations complete_fops = {
    .owner = THIS_MODULE,
    .open = complete_device_open,
    .release = complete_device_release,
    .read = complete_device_read,
    .write = complete_device_write,
};

// 模块初始化
static int __init complete_device_init(void) {
    int ret;
    dev_t dev_num;
    
    // 分配设备号
    ret = alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME);
    if (ret < 0) {
        printk(KERN_ALERT "无法分配设备号\n");
        return ret;
    }
    
    major_number = MAJOR(dev_num);
    
    // 分配设备数据
    device_data = kzalloc(sizeof(*device_data), GFP_KERNEL);
    if (!device_data) {
        ret = -ENOMEM;
        goto cleanup_device_number;
    }
    
    // 初始化互斥锁和缓冲区
    mutex_init(&device_data->lock);
    device_data->buffer_len = 0;
    
    // 初始化字符设备
    cdev_init(&device_data->cdev, &complete_fops);
    device_data->cdev.owner = THIS_MODULE;
    
    // 添加字符设备
    ret = cdev_add(&device_data->cdev, dev_num, 1);
    if (ret < 0) {
        printk(KERN_ALERT "无法添加字符设备\n");
        goto cleanup_device_data;
    }
    
    // 创建设备类
    device_class = class_create(THIS_MODULE, CLASS_NAME);
    if (IS_ERR(device_class)) {
        ret = PTR_ERR(device_class);
        printk(KERN_ALERT "无法创建设备类\n");
        goto cleanup_cdev;
    }
    
    // 创建设备文件
    device_create(device_class, NULL, dev_num, NULL, DEVICE_NAME);
    
    printk(KERN_INFO "完整设备驱动加载成功,主设备号: %d\n", major_number);
    return 0;

cleanup_cdev:
    cdev_del(&device_data->cdev);
cleanup_device_data:
    kfree(device_data);
cleanup_device_number:
    unregister_chrdev_region(dev_num, 1);
    return ret;
}

// 模块清理
static void __exit complete_device_exit(void) {
    dev_t dev_num = MKDEV(major_number, 0);
    
    // 销毁设备文件
    device_destroy(device_class, dev_num);
    
    // 销毁设备类
    class_destroy(device_class);
    
    // 删除字符设备
    cdev_del(&device_data->cdev);
    
    // 释放设备数据
    kfree(device_data);
    
    // 释放设备号
    unregister_chrdev_region(dev_num, 1);
    
    printk(KERN_INFO "完整设备驱动卸载成功\n");
}

module_init(complete_device_init);
module_exit(complete_device_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Complete Character Device Driver Example");

三、综合实战:多线程与驱动交互

3.1 用户空间与内核空间通信

c 复制代码
// 用户空间测试程序
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

#define DEVICE_PATH "/dev/complete_device"

void *writer_thread(void *arg) {
    int fd = open(DEVICE_PATH, O_WRONLY);
    if (fd < 0) {
        perror("打开设备失败");
        return NULL;
    }
    
    char message[256];
    for (int i = 0; i < 10; i++) {
        snprintf(message, sizeof(message), 
                "写者线程 %lu 消息 %d", (unsigned long)pthread_self(), i);
        
        ssize_t written = write(fd, message, strlen(message));
        if (written < 0) {
            perror("写入失败");
            break;
        }
        
        printf("写入: %s\n", message);
        usleep(100000); // 100ms
    }
    
    close(fd);
    return NULL;
}

void *reader_thread(void *arg) {
    int fd = open(DEVICE_PATH, O_RDONLY);
    if (fd < 0) {
        perror("打开设备失败");
        return NULL;
    }
    
    char buffer[256];
    for (int i = 0; i < 10; i++) {
        ssize_t read_bytes = read(fd, buffer, sizeof(buffer) - 1);
        if (read_bytes < 0) {
            perror("读取失败");
            break;
        }
        
        if (read_bytes > 0) {
            buffer[read_bytes] = '\0';
            printf("读者线程 %lu 读取: %s\n", 
                   (unsigned long)pthread_self(), buffer);
        }
        
        usleep(150000); // 150ms
    }
    
    close(fd);
    return NULL;
}

int main() {
    pthread_t writers[2], readers[2];
    
    // 创建写者线程
    for (int i = 0; i < 2; i++) {
        pthread_create(&writers[i], NULL, writer_thread, NULL);
    }
    
    // 创建读者线程
    for (int i = 0; i < 2; i++) {
        pthread_create(&readers[i], NULL, reader_thread, NULL);
    }
    
    // 等待所有线程完成
    for (int i = 0; i < 2; i++) {
        pthread_join(writers[i], NULL);
        pthread_join(readers[i], NULL);
    }
    
    return 0;
}

3.2 性能优化与调试技巧

3.2.1 驱动性能优化
c 复制代码
// 使用等待队列优化I/O操作
#include <linux/wait.h>
#include <linux/sched.h>

struct optimized_device_data {
    struct mutex lock;
    wait_queue_head_t read_queue;
    wait_queue_head_t write_queue;
    char buffer[BUFFER_SIZE];
    size_t buffer_len;
    bool data_available;
};

// 优化的读操作
static ssize_t optimized_device_read(struct file *filep, char __user *buffer,
                                    size_t len, loff_t *offset) {
    struct optimized_device_data *data = filep->private_data;
    ssize_t ret;
    DEFINE_WAIT(wait);
    
    if (mutex_lock_interruptible(&data->lock)) {
        return -ERESTARTSYS;
    }
    
    // 等待数据可用
    while (data->buffer_len == 0) {
        prepare_to_wait(&data->read_queue, &wait, TASK_INTERRUPTIBLE);
        mutex_unlock(&data->lock);
        
        schedule(); // 让出CPU
        
        finish_wait(&data->read_queue, &wait);
        
        if (signal_pending(current)) {
            return -ERESTARTSYS;
        }
        
        if (mutex_lock_interruptible(&data->lock)) {
            return -ERESTARTSYS;
        }
    }
    
    // 读取数据
    ret = min(len, data->buffer_len - *offset);
    if (copy_to_user(buffer, data->buffer + *offset, ret)) {
        ret = -EFAULT;
    } else {
        *offset += ret;
    }
    
    mutex_unlock(&data->lock);
    return ret;
}
3.2.2 调试与日志
c 复制代码
// 条件编译的调试输出
#ifdef DEBUG
#define dbg_print(fmt, args...) \
    printk(KERN_DEBUG "%s:%d: " fmt, __FILE__, __LINE__, ##args)
#else
#define dbg_print(fmt, args...) 
#endif

// 带级别的调试输出
#define DEVICE_DEBUG_LEVEL 2

#if DEVICE_DEBUG_LEVEL >= 1
#define debug_error(fmt, args...) \
    printk(KERN_ERR "ERROR: " fmt, ##args)
#else
#define debug_error(fmt, args...)
#endif

#if DEVICE_DEBUG_LEVEL >= 2  
#define debug_info(fmt, args...) \
    printk(KERN_INFO "INFO: " fmt, ##args)
#else
#define debug_info(fmt, args...)
#endif

#if DEVICE_DEBUG_LEVEL >= 3
#define debug_verbose(fmt, args...) \
    printk(KERN_DEBUG "VERBOSE: " fmt, ##args)
#else
#define debug_verbose(fmt, args...)
#endif

// 在驱动中使用
static int debug_probe(struct platform_device *pdev) {
    debug_info("开始设备探测\n");
    
    // 探测代码...
    
    if (error_condition) {
        debug_error("探测失败: 错误代码 %d\n", error_code);
        return error_code;
    }
    
    debug_info("设备探测成功\n");
    return 0;
}

四、最佳实践与总结

4.1 多线程编程最佳实践

  1. 资源管理

    • 始终在创建线程前初始化同步对象
    • 确保在所有退出路径上释放资源
    • 使用RAII模式管理资源
  2. 错误处理

    • 检查所有线程相关函数的返回值
    • 实现适当的错误恢复机制
    • 使用线程局部存储存储错误信息
  3. 性能考虑

    • 避免过度创建线程
    • 使用线程池管理线程生命周期
    • 减少锁的持有时间

4.2 驱动开发最佳实践

  1. 代码质量

    • 遵循Linux内核编码风格
    • 使用适当的内核API
    • 实现完整的错误处理
  2. 安全性

    • 验证所有用户空间输入
    • 使用内核的安全函数
    • 防止缓冲区溢出
  3. 可维护性

    • 提供清晰的模块文档
    • 实现适当的调试支持
    • 保持代码的模块化

4.3 综合建议

多线程编程要点

  • 理解数据竞争和避免方法
  • 掌握各种同步机制的使用场景
  • 学会调试多线程程序

驱动开发要点

  • 熟悉Linux设备模型
  • 掌握字符设备驱动开发流程
  • 理解设备树的使用方法

集成开发建议

  • 在用户空间充分测试驱动功能
  • 使用适当的同步机制保护共享资源
  • 实现完善的错误处理和日志记录

结论

多线程编程和Linux驱动开发是嵌入式系统开发中的核心技术。通过本文的详细讲解,我们深入探讨了:

  1. 多线程编程:从基础的线程创建管理到高级的同步机制和线程池实现
  2. 驱动开发:从简单的内核模块到完整的字符设备驱动开发
  3. 综合应用:用户空间与内核空间的交互,性能优化和调试技巧

掌握这些技术需要理论学习和实践经验的结合。建议开发者从简单的例子开始,逐步深入理解各个概念,在实际项目中应用这些技术,不断提升自己的技能水平。

嵌入式Linux开发是一个持续学习的过程,多线程编程和驱动开发作为其中的核心技术,值得投入时间和精力深入掌握。希望本文能为您的学习之路提供有价值的参考和指导。

相关推荐
还债大湿兄2 小时前
阿里通义千问调用图像大模型生成轮动漫风格 python调用
开发语言·前端·python
okseekw2 小时前
字面量的初步认识
java
鸭子程序员2 小时前
c++ 算法
开发语言·c++·算法
搬砖ing换来金砖2 小时前
Python入门-Task02
开发语言·python
雨中散步撒哈拉2 小时前
17、做中学 | 初三下期 Golang文件操作
开发语言·后端·golang
倚肆2 小时前
Spring Boot CORS 配置详解:CorsConfigurationSource 全面指南
java·spring boot·后端
q***72193 小时前
Spring Boot(快速上手)
java·spring boot·后端
CoderYanger3 小时前
C.滑动窗口——1423. 可获得的最大点数
java·开发语言·算法·leetcode·1024程序员节
全栈陈序员3 小时前
【Python】基础语法入门(九)—— 代码规范、调试技巧与性能初探
开发语言·python·代码规范