一、多线程编程深入解析
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 多线程编程最佳实践
-
资源管理:
- 始终在创建线程前初始化同步对象
- 确保在所有退出路径上释放资源
- 使用RAII模式管理资源
-
错误处理:
- 检查所有线程相关函数的返回值
- 实现适当的错误恢复机制
- 使用线程局部存储存储错误信息
-
性能考虑:
- 避免过度创建线程
- 使用线程池管理线程生命周期
- 减少锁的持有时间
4.2 驱动开发最佳实践
-
代码质量:
- 遵循Linux内核编码风格
- 使用适当的内核API
- 实现完整的错误处理
-
安全性:
- 验证所有用户空间输入
- 使用内核的安全函数
- 防止缓冲区溢出
-
可维护性:
- 提供清晰的模块文档
- 实现适当的调试支持
- 保持代码的模块化
4.3 综合建议
多线程编程要点:
- 理解数据竞争和避免方法
- 掌握各种同步机制的使用场景
- 学会调试多线程程序
驱动开发要点:
- 熟悉Linux设备模型
- 掌握字符设备驱动开发流程
- 理解设备树的使用方法
集成开发建议:
- 在用户空间充分测试驱动功能
- 使用适当的同步机制保护共享资源
- 实现完善的错误处理和日志记录
结论
多线程编程和Linux驱动开发是嵌入式系统开发中的核心技术。通过本文的详细讲解,我们深入探讨了:
- 多线程编程:从基础的线程创建管理到高级的同步机制和线程池实现
- 驱动开发:从简单的内核模块到完整的字符设备驱动开发
- 综合应用:用户空间与内核空间的交互,性能优化和调试技巧
掌握这些技术需要理论学习和实践经验的结合。建议开发者从简单的例子开始,逐步深入理解各个概念,在实际项目中应用这些技术,不断提升自己的技能水平。
嵌入式Linux开发是一个持续学习的过程,多线程编程和驱动开发作为其中的核心技术,值得投入时间和精力深入掌握。希望本文能为您的学习之路提供有价值的参考和指导。