网络公司专业做网站,发布平台是什么,网站搜索优化方案,运营方案怎么做Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 提到锁”#xff0c;可能想到的更多的是限制。现实中#xff0c;生活中锁也 存在于身边的方方面面。正所谓没有规矩不成方圆#xff0c; 没有身边的这些锁可能想到的更多的是限制。现实中生活中锁也 存在于身边的方方面面。正所谓没有规矩不成方圆 没有身边的这些锁这些限制社会将会变得无序、混乱。为了规范这些无序和混乱就得根据实际情况制定规则制度甚至法律来进行束缚和限制。正如本篇笔记要讲解的内容一样Linux内核采用一定的方式方法函数制定了这些所谓的规则才能使程序变得更流畅。 本篇笔记主要学习Linux处理并发与竞争的机制。主要内容包括原子操作、自旋锁、信号量和互斥体。 一、并发与竞争
1.简介 Linux是多任务操作系统存在多个任务同时访问同一内存区域造成这些任务会相互覆盖这段内存中的数据从而造成内存数据的混乱。多个线程同时操作临界区就会发生竞争竞争并发导致。
2.保护什么 保护共享资源数据。
二、原子操作
1.简介 原子操作就是指不能再进一步分割的操作用于变量和位操作。
2.原子整形操作API函数
原子整形操作API函数 函数描述ATOMIC_INIT(init i)定义原子变量的时候对其进行初始化。int atomic_read(atomic_t *v)读取v的值并返回。void atomic_set(atomic_t *v,int i)向v写入i值。void atomic_add(atomic_t *v)给v加上i值。void atomic_sub(atomic_t *v)给v减去i值。void atomic_inc(atomic_t *v)自增void atomic_dec(atomic_t *v)自减void atomic_inc_return(atomic_t *v)自增并返回v值void atomic_dec_return(atomic_t *v)自减并返回v值int atomic_sub_and_test(int i,atomic_t *v)从v减i如果结果为0就返回真否则返回为假int atomic_dec_and_test(int i,atomic_t *v)从v减1如果结果为0就返回真否则返回为假int atomic_add_and_test(int i,atomic_t *v)从v加i如果结果为0就返回真否则返回为假int atomic_inc_and_test(int i,atomic_t *v)从v加1如果结果为0就返回真否则返回为假
3.原子位操作API函数
原子位操作API函数 函数描述void set_bit(int nr,void *p)将p地址的第nr位置1void clear_bit(int nr,void *p)将p地址的第nr位清零void change_bit(int nr,void *p)将p地址的第nr位翻转int test_bit(int nr,void *p)获取p地址的第nr位的值int test_and_set(int nr,void *p)将p地址的nr位置1并返回nr位原来的值int test_and_clear(int nr,void *p)将p地址的nr位清零并返回nr位原来的值int test_and_change(int nr,void *p)将p地址的第nr位翻转并返回nr位原来的值
三、自旋锁
1.简介 当一个线程要访问某个共享资源的时候首先要先获取相应的锁锁只能被一个线程持有只要此线程不释放拥有的锁那么其他的线程就不能获取此锁。 自旋---原地打转 缺点时间短。 使用结构体spinlock_t表示自旋锁。
2.自旋锁API函数
自旋锁API函数 函数描述DEFINE_SPINLOCK(spinlock_t lock)定义并初始化一个自选变量int spin_lock_init(spinlock_t *lock)初始化自旋锁 void spin_lock(spinlock_t *lock) 获取指定的自旋锁加锁void spin_unlock(spinlock_t *lock)释放指定的自旋锁int spin_trylock(spinlock_t *lock)尝试获取指定的自旋锁如果没有获取就返回0int spin_is_locked(spinlock_t *lock) 检查指定的自旋锁是否被获取如果没有被获取就返回非0否则返回0 自旋锁适用于线程与线程之间被自旋锁保护的临界区一定不能调用任何能引起睡眠和阻塞的API函数否则会导致死锁的发生。 自旋锁会自动禁止抢占。 中断里面可以使用自旋锁但在中断里面使用自旋锁的时候在获取之前一定要先禁止本地中断。相应的API函数如下
函数描述void spin_lock_irqsave(spinlock_t *lock,unsigned long flags)保存中断状态禁止本地中断并获取自旋锁。void spin_unlock_irqrestore(spinlock_t *lock,unsigned long flags)将中断状态恢复打以前状态并且激活本地中断释放自旋锁。 下半部也会竞争共享资源下半部使用自旋锁的API函数有
函数 描述void spin_lock_bh(spinlock_t *lock)关闭下半部并获取自旋锁void spin_unlock_bh(spinlock_t lock)打开下半部并释放自旋锁
3.其他类型的锁 实际应用中用的不多多的是在Linux内核中使用。
1、读写自旋锁
2、顺序锁
4.使用注意事项
1、持有时间不能太长
2、自旋锁保护的临界区内部能调用任何可能导致线程休眠的API函数否则可能会导致死锁。
3、不能递归申请自旋锁
4、多核SOC编写程序
四、信号量
1.简介 信号量常用于对共享资源的访问。 信号量可以使线程进入休眠状态。 信号量的开销比自旋锁要大。 信号量特点
1、适用于占用资源比较长的场所。
2、不能用于中断中。 通过信号量控制访问资源的线程数。 不能用于互斥访问。
2.信号量API函数 使用semaphore结构体表示信号量。相关的API函数如下
函数描述DEFINE_SEMAPHORE(name)定义一个信号量并设置信号量的值为1void sema_init(struct semaphore *sem,int val)初始化信号量sem,设置信号量的值为val.void down(struct semaphore *sem)获取信号量不能用在中断中使用int down_trylock(struct semaphore *sem)尝试获取信号量能获取就返回0.如果不能返回非0并且不会进入休眠。int down_interruptible(struct semaphore *sem)获取信号量进入休眠以后是可以被信号打断的。void up(struct semaphore *sem)释放信号量
五、互斥体
1.简介 一次只有一个线程访问共享资源不能递归申请。需要互斥访问的时候建议使用mutex. 注意以下几点
1、不能在中断中使用。
2、保护的临界区可以调用引起阻塞的API函数。
3、必须由mutex的持有者释放mutex。mutex不能递归上锁和解锁。
2.互斥体API函数 相关的API函数有
函数描述DEFINE_MUXTEX(name)定义并初始化一个mutex变量void mutex_init(mutex *lock)初始化mutexvoid mutex_lock(struct mutex *lock)获取mutex 上锁 获取不到就休眠void mutex_unlock(struct mutex *lock)释放mutex 解锁iint mutex_trylock(struct mutex *lock)尝试获取mutex 成功返回0 失败返回0int mutex_is_locked(struct mutex *lock)判断mutex是否被获取 获取返回1 否则返回0int mutex_lock_interruptible(struct mutex *lock)使用此函数获取信号量失败进入休眠以后可以被信号打断
六、总结 本篇笔记主要学习了相关的概念及API函数并没有相关的案例进行说明。案例将在下一篇笔记中给出。本篇笔记主要内容包括原子操作、自旋锁、信号量和互斥体。