参考资料: 《正点原子Linux驱动教程》 《宋宝华 Linux设备驱动开发详解》 原子操作只能对整型变量或者bit位进行保护,但是实际使用中,不可能只有整型变量或者bit位等临界区 自旋锁spinlock也是一种典型的对临界资源进行互斥访问的手段,其名称来源自它的工作方式。 当一个线程要访问某个共享资源的时候首先要先获取相应的锁,锁只能被一个线程持有,只要此线程不释放持有的锁,那么其他的线程就不能获取此锁。对于自旋锁而言,如果自旋锁正在被线程 A 持有,线程 B 想要获取自旋锁,那么线程 B 就会处于忙循环-旋转-等待状态 自旋锁简化定义:
typedef struct { arch_spinlock_t raw_lock; } spinlock_t;
自旋锁的相关操作:
spinlock_t lock; // 定义自旋锁 spin_lock_init(lock) // 初始化自旋锁 spin_lock(lock) // 获取自旋锁 spin_unlock(lock) // 释放自旋锁
自旋锁使用demo:
DEFINE_SPINLOCK(lock) /* 定义并初始化一个锁 */ /* 线程 A */ void functionA (){ unsigned long flags; /* 中断状态 */ spin_lock_irqsave(&lock, flags) /* 获取锁 */ /* 临界区 */ spin_unlock_irqrestore(&lock, flags) /* 释放锁 */ } /* 中断服务函数 */ void irq() { spin_lock(&lock) /* 获取锁 */ /* 临界区 */ spin_unlock(&lock) /* 释放锁 */ }自旋锁主要针对SMP或单CPU但内核可抢占的情况,对于单CPU和内核不支持抢占的系统,自旋锁退化为空操作。自旋锁持有期间内核抢占将被禁止。在多核SMP的情况下,任何一个核拿到了自旋锁,该核上的抢占调度也被暂时禁止了,但是没有禁止另外的核抢占调度 尽管用了自旋锁可以保证临界区不受别的CPU和本CPU内抢占进程的打扰,但是得到锁的代码路径在执行临界区的时候,还可能收到中断的影响,为了防止这种影响,就出现了自旋锁的衍生: 本地中断:自旋锁单个核心的中断 在SMP编程中,如果进程和中断都有可能访问同一片临界资源时,一般在进程上下文调用spin_lock_irqsave()和spin_lock_irqrestore(),在中断上下文调用spin_lock()和spin_unlock() 编写驱动程序时,需要注意下面的几个问题: 1、自旋锁实际上是忙等待,CPU在等待自旋锁时不做任何有用的工作,仅仅是等待。因此,只有在占用锁的时间极短的情况下,使用自旋锁才是合理的。当临界区很大或共享设备的时候,需要较长时间占用锁,这种情况使用自旋锁会降低系统性能 2、自旋锁可能导致系统死锁,引发这个问题最常见的情况是递归使用一个自旋锁,即如果一个已经拥有某个自旋锁的CPU想第二次获取到这个自旋锁,则该CPU将死锁 3、自旋锁锁定期间不能调度会引起进程调度的函数,如果进程获取自旋锁之后再阻塞,如使用copy_from_user()、copy_to_user()、kmalloc()和msleep()等函数,则会导致系统的崩溃
spinlock测试demo:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/spinlock.h> #include <linux/kthread.h> #include <linux/delay.h> DEFINE_SPINLOCK(my_spinlock); static int shared_data = 0; static struct task_struct *my_thread1; static struct task_struct *my_thread2; int my_thread_func(void *data) { int i; for (i = 0; i < 5; i++) { spin_lock(&my_spinlock); shared_data++; printk(KERN_INFO "Thread %s: Incrementing shared data - %d\n", (char *)data, shared_data); spin_unlock(&my_spinlock); msleep(1000); // 模拟一些工作 } do_exit(0); return 0; } static int __init demo_init(void) { printk(KERN_INFO "Demo: Initializing driver\n"); // 创建两个内核线程 my_thread1 = kthread_run(my_thread_func, "1", "my_thread1"); my_thread2 = kthread_run(my_thread_func, "2", "my_thread2"); return 0; } static void __exit demo_exit(void) { if (my_thread1) kthread_stop(my_thread1); if (my_thread2) kthread_stop(my_thread2); printk(KERN_INFO "Demo: Exiting driver\n"); } module_init(demo_init); module_exit(demo_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("lethe1203"); MODULE_DESCRIPTION("spinlock demo");
标签:lock,线程,自旋,my,spin,spinlock From: https://www.cnblogs.com/lethe1203/p/18095274