并发同步处理方法
并发:多个执行单元同时或并行运行 竞争:多个执行单元同时并行的访问某个共享资源,导致竞争,竟态。 同步:多个执行单元协调动作,相互配合,串行的共同完成一个任务。 发生竟态时,如下手段对临界资源做同步处理。
1、原子量 用于临界资源数量控制 atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0 atomic_read(atomic_t *v); //返回原子变量的值 void atomic_inc(atomic_t *v); //原子变量增加1 void atomic_dec(atomic_t *v); //原子变量减少1 int atomic_dec_and_test(atomic_t *v); //自减操作后测试其是否为0,为0则返回true,否则返回false。
2、自旋spin_lock_init锁
CPU 获取不到自旋锁,会忙等待。获取自旋锁后,不受别的CPU和本CPU的进程抢占打扰,但可以被中断和底半部抢占,是否受软中断打扰待确认。获取自旋锁后,进行调度,抢占以及在等待队列上睡眠都是非法的。spin_lock_init(); spin_lock spin_unlock spin_lock_irq 禁止中断 spin_unlock_irq 恢复中断 spin_lock_irqsave spin_unlock_irqrestore spin_lock_bh = spin_lock + local_bh_disable 关底半部 spin_unlock_bh = spin_unlock + local_bh_enable 开底半部
如果进程获得自旋锁之后再阻塞,如调用copy_from_user()、copy_to_user()、kmalloc()和msleep()等函数,则可能导致内核的崩溃
3、互斥锁
互斥锁用来保证在任一时刻只能有一个线程访问或执行临界区互斥锁用于进程上下文,不能用于中断上下文、也不能持有自旋锁情况下使用互斥锁struct mutex my_mutex; mutex_init(&my_mutex);
DEFINE_MUTEX(mutexname) //以上两句的合二为一
mutex_lock() mutex_lock_interruptible() mutex_lock_killable() mutex_trylock() //返回1,代码获取互斥锁成功 mutex_destroy mutex_unlock
4、信号量 信号量(semphore)是用于保护临界区的一种常用方法 信号量只能用于进程上下文,不能用于中断上下文,也不能持有自旋锁情况下使用信号量。 struct semaphore sem; void sema_init(struct semaphore *sem, int val)
DEFINE_SEMAPHORE(name) //信号量资源值初始化为1 ,此时与互斥锁类似
void down(struct semaphore *sem); //获取信号量,资源值减1 void down_interruptible(struct semephore *sem)//获取信号量,资源值减1,睡眠后可被信号中断 void down_trylock(struct semaphore *sem);//不会导致调用者睡眠,可以在中断上下文使用,返回0 获取信号量成功 void down_timeout(struct semaphore *sem, long jiffies) // 超时,返回 int down_killable(struct semaphore *sem) // void up(struct semaphore *sem);//释放信号量,资源值加1
#include <linux/device.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h> #include <linux/list.h> #include <linux/types.h> #include <linux/delay.h> #include <linux/timer.h> #include <linux/slab.h> #include <linux/atomic.h> #include <linux/spinlock.h> #include <linux/irq.h> #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/semaphore.h> MODULE_AUTHOR("xyzeng"); MODULE_LICENSE("Dual BSD/GPL"); spinlock_t mylock; struct semaphore mysem; DEFINE_MUTEX(mymutex); void timer_func(struct timer_list * timelist) { printk("timer_func enter\n"); spin_lock(&mylock); // 若中断拿锁,自旋 导致系统阻塞 printk("timer_func spin_lock get enter\n"); spin_unlock(&mylock); printk("timer_func spin_lock out \n"); up(&mysem); //释放信号量 code_case_concurrent_init执行完成 printk("timer_func mutex_lock start! \n"); mutex_lock(&mymutex); // 此处使用互斥锁是非法的、当能正常获取锁时,能正常执行,正规代码禁止使用 mdelay(30000);// 中断中可以使用忙等延时,不能使用睡眠。 mutex_unlock(&mymutex); printk("timer_func mutex_lock out \n"); } DEFINE_TIMER(my_timer,timer_func); irqreturn_t irq_srv(int irq, void * dev_id) { printk("irq_srv enter\n"); spin_lock(&mylock); // 若中断拿锁,自旋 导致系统阻塞 printk("irq_srv spin_lock get enter\n"); spin_unlock(&mylock); printk("irq_srv spin_lock out \n"); printk("irq_srv will get mutex_lock ! \n"); #if 1 if(mutex_trylock(&mymutex) == 1) { //使用trylock 能正常执行 mdelay(3000); // 中断中可以使用忙等延时,不能使用睡眠。 mutex_unlock(&mymutex); printk("irq_srv mutex_lock out \n"); } else printk("irq_srv mutex_lock out \n"); #else mutex_lock(&mymutex); //此处使用互斥锁是非法的,timer_func的软中断可以被硬中断抢断,软中断获取了互斥锁,此处就会系统崩溃 printk("irq_srv mutex_lock start! \n"); mdelay(3000);// 中断中可以使用忙等延时,不能使用睡眠。 mutex_unlock(&mymutex); printk("irq_srv mutex_lock out \n"); #endif return IRQ_HANDLED; } int gpio_irq,irq; static int code_case_concurrent_init(void) { static atomic_t canopen = ATOMIC_INIT(1); atomic_inc(&canopen); int r = atomic_read(&canopen); printk("atomic_read:%d\n",r); atomic_dec(&canopen); if(atomic_dec_and_test(&canopen)){ printk("atomic_dec_and_test == 0\n"); } gpio_irq = 4*32 + 1 ; gpio_free(gpio_irq); int ret = gpio_request(gpio_irq,"gpio_irq"); printk("gpio_request:%d\n",ret); if(ret == 0){ irq = gpio_to_irq(gpio_irq); printk("gpio_to_irq:%d\n",irq); irq_set_irq_type(irq,IRQ_TYPE_EDGE_RISING); ret = request_irq(irq,irq_srv,IRQF_SHARED,"hello",&irq); //最后一个参数不能为NULL printk("request_irq:%d\n",ret); } sema_init(&mysem, 1); //信号量资源初始化为1 spin_lock_init(&mylock); spin_lock(&mylock); printk("spin_lock get!\n"); my_timer.expires = jiffies + 2*HZ; // 2s 后 进入时钟软中断 add_timer(&my_timer); // msleep(1000);//非法操作 down(&mysem);// 非法操作,若获取不到资源,则会崩溃,此处继续执行 long timeout = jiffies + 5 *HZ; while(time_before(jiffies,timeout)); // 忙等待10s printk("spin_unlock time out! 0\n"); spin_unlock(&mylock); //经在单核CPU上测试,timer在unlock后才执行。 printk("spin_unlock out!\n"); down(&mysem);// 系统在此处阻塞 timer_func执行 printk("get sem OK!\n"); // 中断触发后,有该打印。 return 0; } static void code_case_concurrent_exit(void) { printk("[%s,%d] enter!\n",__FUNCTION__,__LINE__); free_irq(irq,&irq); } module_init(code_case_concurrent_init); module_exit(code_case_concurrent_exit);