【Linux 驱动中的并发与竞争】

60 阅读15分钟

在 Linux 驱动开发领域,驱动程序的稳定运行是保障系统正常工作的关键。然而,随着硬件设备功能的日益复杂和多任务系统的广泛应用,并发与竞争问题逐渐成为影响驱动稳定性和可靠性的重要因素。这些问题若处理不当,可能导致数据错误、系统崩溃等严重后果。本文将深入探讨 Linux 驱动中并发与竞争产生的原因、具体场景,并详细介绍相应的解决方案,帮助开发者有效应对这些挑战。

一、并发与竞争的概念

1.1 并发

并发是指在同一时间段内,多个执行单元(如进程、线程、中断处理程序等)同时对系统资源进行访问或操作。在 Linux 驱动中,并发情况十分常见,例如多个用户空间进程同时访问设备驱动、进程与中断处理程序同时操作设备资源等。这些并发操作虽然提高了系统的效率,但也带来了潜在的风险。

1.2 竞争

竞争(Race Condition)则是并发操作带来的不良结果,当多个执行单元同时访问共享资源(如内存变量、硬件寄存器),并且这些访问的顺序和时机不确定,导致最终结果依赖于执行单元的执行顺序时,就会出现竞争条件。竞争条件可能导致数据不一致、程序逻辑错误等问题,严重影响驱动的正常运行。

二、并发与竞争产生的原因

2.1 多任务环境

Linux 作为多任务操作系统,支持多个进程和线程同时运行。当这些进程或线程同时访问驱动程序中的共享资源时,就可能引发并发与竞争问题。例如,两个进程同时对设备的计数器进行加 1 操作,如果没有适当的保护措施,可能会导致计数器的值出现错误。

2.2 中断的异步性

中断是硬件设备向 CPU 发送信号的一种机制,用于通知 CPU 发生了特定事件。中断处理程序的执行具有异步性,它可能在任何时刻打断进程的正常执行。当进程正在访问设备资源时,若此时中断发生,中断处理程序也对同一资源进行操作,就容易产生竞争。比如,进程正在读取设备的状态寄存器,中断处理程序却在此时修改了该寄存器的值,可能导致进程读取到错误的状态信息。

2.3 内核抢占

Linux 内核支持抢占机制,即当高优先级任务准备好运行时,正在执行的低优先级任务可以被暂停,以便高优先级任务优先执行。在驱动程序执行过程中,如果发生内核抢占,被抢占的任务可能正在访问共享资源,而新调度的任务也试图访问同一资源,从而引发竞争。

三、并发与竞争的具体场景及解决方案

3.1 进程间并发与竞争

场景描述 多个用户空间进程同时打开设备文件并进行读写操作,若驱动程序没有对共享资源进行保护,就会出现竞争。例如,一个字符设备驱动维护着一个缓冲区用于存储数据,多个进程同时向缓冲区写入数据,可能导致数据覆盖或混乱。 解决方案:信号量(Semaphore) 信号量是一种经典的同步机制,通过一个计数器来控制对共享资源的访问。在驱动中,可以使用struct semaphore定义信号量,并通过sem_init函数进行初始化。在访问共享资源前,调用down函数获取信号量,如果信号量的值为 0,则调用进程会被阻塞,直到信号量被释放;在访问完共享资源后,调用up函数释放信号量,唤醒等待的进程。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/semaphore.h>

#define DEVICE_NAME "simple_char_dev"
#define DEVICE_SIZE 1024

struct semaphore my_sem;

 struct simple_dev_t {
    struct cdev cdev;
    dev_t dev_num;
    struct class *class;
    struct device *device;
    char buffer[DEVICE_SIZE]; // 数据缓冲区
} ;


static struct simple_dev_t simple_dev;

static int my_char_open(struct inode *inode, struct file *filp) {
    struct simple_dev_t *dev = container_of(inode->i_cdev, struct simple_dev_t, cdev);
    filp->private_data = dev;
    return 0;
}

static ssize_t my_char_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) {
    struct simple_dev_t *dev = filp->private_data;
    // 获取信号量
    down(&my_sem);
    // 进行数据写入操作
    if (copy_from_user(dev->buffer, buf, count)) {
        // 释放信号量
        up(&my_sem);
        return -EFAULT;
    }
    printk(KERN_INFO "my_char_write buffer = %s\n", dev->buffer);
    // 释放信号量
    up(&my_sem);
    return count;
}

static const struct file_operations my_char_fops = {
   .owner = THIS_MODULE,
   .open = my_char_open,
   .write = my_char_write,
};

static int __init my_char_driver_init(void) {
    // 初始化信号量
    sema_init(&my_sem, 1);
    int result;
    
    // 动态分配设备号
    result = alloc_chrdev_region(&simple_dev.dev_num, 0, 1, DEVICE_NAME);
    if (result < 0) {
        printk(KERN_ERR "my_char_driver_init Failed to allocate major number\n");
        return result;
    }
    
    printk(KERN_INFO "my_char_driver_init Allocated major number: %d\n", MAJOR(simple_dev.dev_num));
    
    // 初始化cdev结构
    cdev_init(&simple_dev.cdev, &my_char_fops);
    simple_dev.cdev.owner = THIS_MODULE;
    
    // 添加字符设备
    result = cdev_add(&simple_dev.cdev, simple_dev.dev_num, 1);
    if (result < 0) {
        printk(KERN_ERR "my_char_driver_init Failed to add cdev\n");
        unregister_chrdev_region(simple_dev.dev_num, 1);
        return result;
    }
    
    // 创建类
    simple_dev.class = class_create(THIS_MODULE, DEVICE_NAME);
    if (IS_ERR(simple_dev.class)) {
        printk(KERN_ERR "my_char_driver_init Failed to create class\n");
        cdev_del(&simple_dev.cdev);
        unregister_chrdev_region(simple_dev.dev_num, 1);
        return PTR_ERR(simple_dev.class);
    }
    
    // 创建设备节点
    simple_dev.device = device_create(simple_dev.class, NULL, simple_dev.dev_num, NULL, DEVICE_NAME);
    if (IS_ERR(simple_dev.device)) {
        printk(KERN_ERR "my_char_driver_init Failed to create device\n");
        class_destroy(simple_dev.class);
        cdev_del(&simple_dev.cdev);
        unregister_chrdev_region(simple_dev.dev_num, 1);
        return PTR_ERR(simple_dev.device);
    }
    return 0;
}

static void __exit my_char_driver_exit(void) {
     // 1. 销毁设备节点
    if (simple_dev.device)
        device_destroy(simple_dev.class, simple_dev.dev_num);
    
    // 2. 销毁设备类
    if (simple_dev.class)
        class_destroy(simple_dev.class);
    
    // 3. 注销字符设备
    cdev_del(&simple_dev.cdev);
    
    // 4. 释放设备号
    unregister_chrdev_region(simple_dev.dev_num, 1);
	
    printk(KERN_INFO "my_char_driver_exit\n");
}

module_init(my_char_driver_init);
module_exit(my_char_driver_exit);


MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A simple driver using concurrent and competition");
MODULE_AUTHOR("cmy");
extern "C"
JNIEXPORT jint JNICALL
Java_com_example_led9_MainActivity_testConcurrency(JNIEnv *env, jobject thiz) {
    // 打开设备文件
    int fd = open("/dev/simple_char_dev", O_WRONLY);
    if (fd < 0) {
        LOGD("open failed");
        return 1;
    }


    write(fd, "testConcurrency", 15);


    close(fd);
    return 0;



}

应用层开启2个线程写入数据。 在这里插入图片描述

3.2 进程与中断处理程序间并发与竞争

场景描述 当进程正在访问设备资源时,中断发生,中断处理程序也需要访问同一资源。例如,一个定时器设备驱动,进程正在读取定时器的当前计数值,此时定时器超时触发中断,中断处理程序需要重置计数器,若不进行同步,可能导致进程读取到错误的计数值。 解决方案:自旋锁(Spin Lock)与中断屏蔽 自旋锁:自旋锁是一种忙等待的锁机制,获取锁的线程在未获得锁时会一直循环等待,直到锁被释放。在 Linux 驱动中,使用spin_lock和spin_unlock函数来操作自旋锁。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/spinlock.h>

#define DEVICE_NAME "simple_char_dev"
#define BUFFER_SIZE 1024


 struct simple_dev_t {
    struct cdev cdev;
    dev_t dev_num;
    struct class *class;
    struct device *device;
    char buffer[BUFFER_SIZE]; // 数据缓冲区
    spinlock_t lock;      // 自旋锁
    int count;            // 缓冲区数据计数
} ;


static struct simple_dev_t simple_dev;

static int my_char_open(struct inode *inode, struct file *filp) {
    struct simple_dev_t *dev = container_of(inode->i_cdev, struct simple_dev_t, cdev);
    filp->private_data = dev;
    return 0;
}

// 读操作
static ssize_t spinlock_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) {
	
    struct simple_dev_t *dev = filp->private_data;
    unsigned long flags;
    ssize_t ret = 0;
    
    // 加锁(中断上下文安全版本)
    spin_lock_irqsave(&dev->lock, flags);
    
    // 临界区:访问共享资源
    if (dev->count > 0) {
        count = min(count, (size_t)dev->count);
        if (copy_to_user(buf, dev->buffer, count)) {
            ret = -EFAULT;
        } else {
            ret = count;
            dev->count -= count;
        }
    }
    
    // 解锁并恢复中断状态
    spin_unlock_irqrestore(&dev->lock, flags);
    
    return ret;
}

// 写操作
static ssize_t spinlock_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) {
	
    struct simple_dev_t *dev = filp->private_data;
    unsigned long flags;
    ssize_t ret = 0;
    
    // 加锁
    spin_lock_irqsave(&dev->lock, flags);
    
    // 临界区:访问共享资源
    if (dev->count + count > BUFFER_SIZE) {
        count = BUFFER_SIZE - dev->count;
    }
    
    if (count > 0) {
        if (copy_from_user(dev->buffer + dev->count, buf, count)) {
            ret = -EFAULT;
        } else {
            ret = count;
            dev->count += count;
        }
    }
    
    // 解锁
    spin_unlock_irqrestore(&dev->lock, flags);
    
    return ret;
}


static const struct file_operations my_char_fops = {
   .owner = THIS_MODULE,
   .open = my_char_open,
   .read = spinlock_read,
   .write = spinlock_write,
};

static int __init my_char_driver_init(void) {
    
    int result;
    
    // 动态分配设备号
    result = alloc_chrdev_region(&simple_dev.dev_num, 0, 1, DEVICE_NAME);
    if (result < 0) {
        printk(KERN_ERR "my_char_driver_init Failed to allocate major number\n");
        return result;
    }
    
    printk(KERN_INFO "my_char_driver_init Allocated major number: %d\n", MAJOR(simple_dev.dev_num));
	
	
    // 初始化自旋锁
    spin_lock_init(&simple_dev.lock);
    
    // 初始化cdev结构
    cdev_init(&simple_dev.cdev, &my_char_fops);
    simple_dev.cdev.owner = THIS_MODULE;
    
    // 添加字符设备
    result = cdev_add(&simple_dev.cdev, simple_dev.dev_num, 1);
    if (result < 0) {
        printk(KERN_ERR "my_char_driver_init Failed to add cdev\n");
        unregister_chrdev_region(simple_dev.dev_num, 1);
        return result;
    }
    
    // 创建类
    simple_dev.class = class_create(THIS_MODULE, DEVICE_NAME);
    if (IS_ERR(simple_dev.class)) {
        printk(KERN_ERR "my_char_driver_init Failed to create class\n");
        cdev_del(&simple_dev.cdev);
        unregister_chrdev_region(simple_dev.dev_num, 1);
        return PTR_ERR(simple_dev.class);
    }
    
    // 创建设备节点
    simple_dev.device = device_create(simple_dev.class, NULL, simple_dev.dev_num, NULL, DEVICE_NAME);
    if (IS_ERR(simple_dev.device)) {
        printk(KERN_ERR "my_char_driver_init Failed to create device\n");
        class_destroy(simple_dev.class);
        cdev_del(&simple_dev.cdev);
        unregister_chrdev_region(simple_dev.dev_num, 1);
        return PTR_ERR(simple_dev.device);
    }
    return 0;
}

static void __exit my_char_driver_exit(void) {
     // 1. 销毁设备节点
    if (simple_dev.device)
        device_destroy(simple_dev.class, simple_dev.dev_num);
    
    // 2. 销毁设备类
    if (simple_dev.class)
        class_destroy(simple_dev.class);
    
    // 3. 注销字符设备
    cdev_del(&simple_dev.cdev);
    
    // 4. 释放设备号
    unregister_chrdev_region(simple_dev.dev_num, 1);
	
    printk(KERN_INFO "my_char_driver_exit\n");
}

module_init(my_char_driver_init);
module_exit(my_char_driver_exit);


MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A simple driver using concurrent and competition");
MODULE_AUTHOR("cmy");

// 写线程函数
void* writer_thread(void* arg) {
    int fd = *(int*)arg;
    char buffer[1000];
    int i;

    for (i = 0; i < 1000; i++) {
        sprintf(buffer, "Message %d from writer\n", i);
        write(fd, buffer, strlen(buffer));
        usleep(1000);  // 短暂休眠
    }

    return NULL;
}

// 读线程函数
void* reader_thread(void* arg) {
    int fd = *(int*)arg;
    char buffer[1000];
    int i, bytes;

    for (i = 0; i < 1000; i++) {
        memset(buffer, 0, 1000);
        bytes = read(fd, buffer, 1000);
        if (bytes > 0) {
            LOGD("Reader got: %s", buffer);
        }
        usleep(2000);  // 短暂休眠
    }

    return NULL;
}

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_led9_MainActivity_testConcurrency1(JNIEnv *env, jobject thiz) {
    int fd;
    pthread_t writer, reader;

    // 打开设备文件
    fd = open("/dev/simple_char_dev", O_RDWR);
    if (fd < 0) {
        LOGD("Failed to open device");
        return -1;
    }

    // 创建读写线程
    pthread_create(&writer, NULL, writer_thread, &fd);
    pthread_create(&reader, NULL, reader_thread, &fd);

    // 等待线程结束
    pthread_join(writer, NULL);
    pthread_join(reader, NULL);

    // 关闭设备
    close(fd);
    return 0;

}

模拟多进程 / 多线程环境下的并发访问。 在这里插入图片描述

3.3 内核抢占导致的并发与竞争

场景描述 当低优先级任务正在访问共享资源时,高优先级任务就绪,内核抢占发生,高优先级任务也试图访问同一资源,从而引发竞争。 解决方案:互斥锁(Mutex)与抢占控制 互斥锁:互斥锁与信号量类似,但它更专注于保护共享资源的互斥访问。使用struct mutex定义互斥锁,mutex_init初始化,mutex_lock获取锁,mutex_unlock释放锁。 抢占控制:在某些情况下,可以通过preempt_disable函数禁止内核抢占,在访问完共享资源后,使用preempt_enable函数恢复内核抢占。不过,过度禁止内核抢占会影响系统的响应性,应谨慎使用。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/mutex.h>

#define DEVICE_NAME "simple_char_dev"
#define BUFFER_SIZE 1024


 struct simple_dev_t {
    struct cdev cdev;
    dev_t dev_num;
    struct class *class;
    struct device *device;
    char buffer[BUFFER_SIZE]; // 数据缓冲区
    struct mutex mutex;   // 互斥锁
    int count;            // 缓冲区数据计数
} ;


static struct simple_dev_t simple_dev;

static int my_char_open(struct inode *inode, struct file *filp) {
    struct simple_dev_t *dev = container_of(inode->i_cdev, struct simple_dev_t, cdev);
    filp->private_data = dev;
    return 0;
}

// 读操作
static ssize_t mutex_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) {
	
    struct simple_dev_t *dev = filp->private_data;
    ssize_t ret = 0;
    
    // 获取互斥锁
    if (mutex_lock_interruptible(&dev->mutex))
        return -ERESTARTSYS;
    
    // 临界区:访问共享资源
    if (dev->count > 0) {
        count = min(count, (size_t)dev->count);
        if (copy_to_user(buf, dev->buffer, count)) {
            ret = -EFAULT;
        } else {
            ret = count;
            // 移动剩余数据
            memmove(dev->buffer, dev->buffer + count, dev->count - count);
            dev->count -= count;
        }
    }
    
    // 释放互斥锁
    mutex_unlock(&dev->mutex);
    
    return ret;
}

// 写操作
static ssize_t mutex_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) {
	
    struct simple_dev_t *dev = filp->private_data;
    ssize_t ret = 0;
    
    // 获取互斥锁
    if (mutex_lock_interruptible(&dev->mutex))
        return -ERESTARTSYS;
    
    // 临界区:访问共享资源
    if (dev->count + count > BUFFER_SIZE) {
        count = BUFFER_SIZE - dev->count;
    }
    
    if (count > 0) {
        if (copy_from_user(dev->buffer + dev->count, buf, count)) {
            ret = -EFAULT;
        } else {
            ret = count;
            dev->count += count;
        }
    }
    
    // 释放互斥锁
    mutex_unlock(&dev->mutex);
    
    return ret;
}

static const struct file_operations my_char_fops = {
   .owner = THIS_MODULE,
   .open = my_char_open,
   .read = mutex_read,
   .write = mutex_write,
};

static int __init my_char_driver_init(void) {
    
    int result;
    
    // 动态分配设备号
    result = alloc_chrdev_region(&simple_dev.dev_num, 0, 1, DEVICE_NAME);
    if (result < 0) {
        printk(KERN_ERR "my_char_driver_init Failed to allocate major number\n");
        return result;
    }
    
    printk(KERN_INFO "my_char_driver_init Allocated major number: %d\n", MAJOR(simple_dev.dev_num));
	
	
    // 初始化互斥锁
    mutex_init(&simple_dev.mutex);
    
    // 初始化cdev结构
    cdev_init(&simple_dev.cdev, &my_char_fops);
    simple_dev.cdev.owner = THIS_MODULE;
    
    // 添加字符设备
    result = cdev_add(&simple_dev.cdev, simple_dev.dev_num, 1);
    if (result < 0) {
        printk(KERN_ERR "my_char_driver_init Failed to add cdev\n");
        unregister_chrdev_region(simple_dev.dev_num, 1);
        return result;
    }
    
    // 创建类
    simple_dev.class = class_create(THIS_MODULE, DEVICE_NAME);
    if (IS_ERR(simple_dev.class)) {
        printk(KERN_ERR "my_char_driver_init Failed to create class\n");
        cdev_del(&simple_dev.cdev);
        unregister_chrdev_region(simple_dev.dev_num, 1);
        return PTR_ERR(simple_dev.class);
    }
    
    // 创建设备节点
    simple_dev.device = device_create(simple_dev.class, NULL, simple_dev.dev_num, NULL, DEVICE_NAME);
    if (IS_ERR(simple_dev.device)) {
        printk(KERN_ERR "my_char_driver_init Failed to create device\n");
        class_destroy(simple_dev.class);
        cdev_del(&simple_dev.cdev);
        unregister_chrdev_region(simple_dev.dev_num, 1);
        return PTR_ERR(simple_dev.device);
    }
    return 0;
}

static void __exit my_char_driver_exit(void) {
     // 1. 销毁设备节点
    if (simple_dev.device)
        device_destroy(simple_dev.class, simple_dev.dev_num);
    
    // 2. 销毁设备类
    if (simple_dev.class)
        class_destroy(simple_dev.class);
    
    // 3. 注销字符设备
    cdev_del(&simple_dev.cdev);
    
    // 4. 释放设备号
    unregister_chrdev_region(simple_dev.dev_num, 1);
	
    printk(KERN_INFO "my_char_driver_exit\n");
}

module_init(my_char_driver_init);
module_exit(my_char_driver_exit);


MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A simple driver using concurrent and competition");
MODULE_AUTHOR("cmy");

3.4 原子操作

原理 原子操作是指不会被系统调度机制打断的操作,其核心特点在于操作的不可分割性,即从开始执行到结束的整个过程中,不会受到其他执行单元的干扰。在 Linux 内核中,原子操作基于底层硬件指令实现,确保对共享资源的访问和修改在单条指令周期内完成,从而避免了并发访问导致的竞争问题。对于简单的变量增减、位操作等场景,原子操作是一种高效且简洁的解决方案。 应用场景 原子操作特别适用于对简单数据类型(如atomic_t类型的整数)进行操作的场景。例如,在统计设备的访问次数、控制设备的开关状态等场景中,原子操作可以确保数据的准确性和一致性。当多个执行单元需要对设备的访问计数进行累加时,使用原子操作可以避免计数错误。 代码示例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/atomic.h>

#define DEVICE_NAME "simple_char_dev"
#define BUFFER_SIZE 1024


 struct simple_dev_t {
    struct cdev cdev;
    dev_t dev_num;
    struct class *class;
    struct device *device;
    atomic_t counter;     // 原子计数器
    atomic_t flag;        // 原子标志位
} ;


static struct simple_dev_t simple_dev;

static int my_char_open(struct inode *inode, struct file *filp) {
    struct simple_dev_t *dev = container_of(inode->i_cdev, struct simple_dev_t, cdev);
    filp->private_data = dev;
    return 0;
}

// 读操作:获取计数器值
static ssize_t my_atomic_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) {
	
    struct simple_dev_t *dev = filp->private_data;
    int value;
    char buffer[32];
    
    // 读取原子变量
    value = atomic_read(&dev->counter);
    snprintf(buffer, sizeof(buffer), "%d\n", value);
    
    // 复制到用户空间
    if (count < strlen(buffer))
        return -EINVAL;
        
    if (copy_to_user(buf, buffer, strlen(buffer)))
        return -EFAULT;
        
    return strlen(buffer);
}

// 写操作:增加计数器或设置标志
static ssize_t my_atomic_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) {

    struct simple_dev_t *dev = filp->private_data;
    char buffer[32];
    
    // 复制到内核空间
    if (count >= sizeof(buffer))
        return -EINVAL;
        
    memset(buffer, 0, sizeof(buffer));
    if (copy_from_user(buffer, buf, count))
        return -EFAULT;
        
    // 根据输入执行不同操作
    if (strncmp(buffer, "inc", 3) == 0) {
        // 原子递增
        atomic_inc(&dev->counter);
    } else if (strncmp(buffer, "dec", 3) == 0) {
        // 原子递减
        atomic_dec(&dev->counter);
    } else if (strncmp(buffer, "set", 3) == 0) {
        // 设置标志
        atomic_set(&dev->flag, 1);
    } else if (strncmp(buffer, "clear", 5) == 0) {
        // 清除标志
        atomic_set(&dev->flag, 0);
    } else {
        return -EINVAL;
    }
    
    return count;
}


static const struct file_operations my_char_fops = {
   .owner = THIS_MODULE,
   .open = my_char_open,
   .read = my_atomic_read,
   .write = my_atomic_write,
};

static int __init my_char_driver_init(void) {
    
    int result;
    
    // 动态分配设备号
    result = alloc_chrdev_region(&simple_dev.dev_num, 0, 1, DEVICE_NAME);
    if (result < 0) {
        printk(KERN_ERR "my_char_driver_init Failed to allocate major number\n");
        return result;
    }
    
    printk(KERN_INFO "my_char_driver_init Allocated major number: %d\n", MAJOR(simple_dev.dev_num));
	
	
    // 初始化原子变量
    atomic_set(&simple_dev.counter, 0);
    atomic_set(&simple_dev.flag, 0);
    
    
    // 初始化cdev结构
    cdev_init(&simple_dev.cdev, &my_char_fops);
    simple_dev.cdev.owner = THIS_MODULE;
    
    // 添加字符设备
    result = cdev_add(&simple_dev.cdev, simple_dev.dev_num, 1);
    if (result < 0) {
        printk(KERN_ERR "my_char_driver_init Failed to add cdev\n");
        unregister_chrdev_region(simple_dev.dev_num, 1);
        return result;
    }
    
    // 创建类
    simple_dev.class = class_create(THIS_MODULE, DEVICE_NAME);
    if (IS_ERR(simple_dev.class)) {
        printk(KERN_ERR "my_char_driver_init Failed to create class\n");
        cdev_del(&simple_dev.cdev);
        unregister_chrdev_region(simple_dev.dev_num, 1);
        return PTR_ERR(simple_dev.class);
    }
    
    // 创建设备节点
    simple_dev.device = device_create(simple_dev.class, NULL, simple_dev.dev_num, NULL, DEVICE_NAME);
    if (IS_ERR(simple_dev.device)) {
        printk(KERN_ERR "my_char_driver_init Failed to create device\n");
        class_destroy(simple_dev.class);
        cdev_del(&simple_dev.cdev);
        unregister_chrdev_region(simple_dev.dev_num, 1);
        return PTR_ERR(simple_dev.device);
    }
    return 0;
}

static void __exit my_char_driver_exit(void) {
     // 1. 销毁设备节点
    if (simple_dev.device)
        device_destroy(simple_dev.class, simple_dev.dev_num);
    
    // 2. 销毁设备类
    if (simple_dev.class)
        class_destroy(simple_dev.class);
    
    // 3. 注销字符设备
    cdev_del(&simple_dev.cdev);
    
    // 4. 释放设备号
    unregister_chrdev_region(simple_dev.dev_num, 1);
	
    printk(KERN_INFO "my_char_driver_exit\n");
}

module_init(my_char_driver_init);
module_exit(my_char_driver_exit);


MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A simple driver using concurrent and competition");
MODULE_AUTHOR("cmy");
// 线程函数:执行原子操作
void* thread_function(void* arg) {
    int fd = *(int*)arg;
    char buffer[32];
    int i;

    // 递增计数器
    for (i = 0; i < 100000; i++) {
        write(fd, "inc", 3);
    }

    // 读取当前值
    memset(buffer, 0, sizeof(buffer));
    read(fd, buffer, sizeof(buffer));
    LOGD("Thread read counter: %s", buffer);

    return NULL;
}


extern "C"
JNIEXPORT jint JNICALL
Java_com_example_led9_MainActivity_testConcurrency2(JNIEnv *env, jobject thiz) {
    int fd;
    pthread_t threads[10];
    int i, result;
    char buffer[32];

    // 打开设备文件
    fd = open("/dev/simple_char_dev", O_RDWR);
    if (fd < 0) {
        LOGD("Failed to open device");
        return -1;
    }

    // 初始化计数器
    write(fd, "clear", 5);

    // 创建多个线程
    for (i = 0; i < 10; i++) {
        result = pthread_create(&threads[i], NULL, thread_function, &fd);
        if (result != 0) {
            LOGD("Failed to create thread");
            close(fd);
            return -1;
        }
    }

    // 等待所有线程完成
    for (i = 0; i < 10; i++) {
        pthread_join(threads[i], NULL);
    }

    // 读取最终结果
    memset(buffer, 0, sizeof(buffer));
    read(fd, buffer, sizeof(buffer));
    LOGD("Final counter value: %s", buffer);

    // 关闭设备
    close(fd);
    return 0;
}

开启10个线程循环写入100000个数据,可以看到最终结果为1000000。 在这里插入图片描述

在上述代码中,使用atomic_inc函数原子性地增加访问计数,使用atomic_dec函数原子性地减少访问计数。通过这种方式,即使在多进程并发访问设备的情况下,也能保证访问计数的准确性。