前言
Linux系统是个多任务操作系统,并发访问带来的问题就是竞争,所谓的临界区就是共享数据段,要保证临界区是原子访问的。主要方法有四种:原子操作,自旋锁,信号量,互斥体。本文主要介绍内核下各方式的常用API及基本用法,帮助大家快速上手。
一、原子操作
原子操作就是指不能在进一步分割的操作,原子操作只能对整形变量或者位进行保护。
1.原子整形操作:
typedef struct {
int counter;
} atomic_t;
操作API如下,对于32位的系统,把接口名的"atomic64_"换成"atomic_"即可。
ATOMIC64_INIT(int i) 定义原子变量的时候对其初始化。
int atomic64_read(atomic64_t *v) 读取 v 的值,并且返回。
void atomic64_set(atomic64_t *v, int i) 向 v 写入 i 值。
void atomic64_add(int i, atomic64_t *v) 给 v 加上 i 值。
void atomic64_sub(int i, atomic64_t *v) 从 v 减去 i 值。
void atomic64_inc(atomic64_t *v) 给 v 加 1,也就是自增。
void atomic64_dec(atomic64_t *v) 从 v 减 1,也就是自减
int atomic64_dec_return(atomic64_t*v) 从 v 减 1,并且返回 v 的值。
int atomic64_inc_return(atomic64_t *v) 给 v 加 1,并且返回 v 的值。
int atomic64_sub_and_test(int i,atomic64_t *v) 从 v 减 i,如果结果为 0 就返回真,否则返回假
int atomic64_dec_and_test(atomic64_t*v) 从 v 减 1,如果结果为 0 就返回真,否则返回假
int atomic64_inc_and_test(atomic64_t*v) 给 v 加 1,如果结果为 0 就返回真,否则返回假
int atomic64_add_negative(int i,atomic64_t *v) 给 v 加 i,如果结果为负就返回真,否则返回假
示例:
atomic_t a = ATOMIC_INT(3);
atomic64_set(&a,10); a赋值为10
atomic64_read(&a); 读出a的值
原子位操作API:
void set_bit(int nr, void *p) 将 p 地址的第 nr 位置 1。
void 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_bit(int nr, void*p) 将 p 地址的第 nr 位置 1,并且返回 nr 位原来的值。
int test_and_clear_bit(int nr,void *p) 将 p 地址的第 nr 位清零,并且返回 nr 位原来的值。
int test_and_change_bit(int nr,void *p) 将 p 地址的第 nr 位翻转,并且返回 nr 位原来的值。
驱动代码示例:
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/of_address.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#define LED_NAME "gpio_init"
#define LED_MAJOR 202
#define LED_MINOR 0
struct led_dev {
struct class * fclass;
struct device * fdevice;
struct cdev * cdev;
dev_t dev_num;
struct device_node * nd;
int major;
int minor;
int gpio_led;
atomic64_t lock;
};
struct led_dev led = {
0};
int led_open (struct inode *a, struct file *b)
{
int val = 0;
printk("lzw led open !!!\n");
if(atomic64_sub_and_test(