原子变量
原子变量atomic_t,定义在linux/types.h中
typedef struct {
int counter;
} atomic_t;
在asm/atomic.h中
// 读取原子变量的值
#define atomic_read(v) READ_ONCE((v)->counter)
// 设置原子变量的值
// 参数 v:操作的量的地址 i:给原子变量的设置值
#define atomic_set(v,i) WRITE_ONCE((v)->counter, (i))
// 原子变量+i
#define atomic_add(i,v) (void)atomic_add_return((i), (v))
// 原子变量-i
#define atomic_sub(i,v) (void)atomic_sub_return((i), (v))
// 原子变量+1
void atomic_inc(atomic_t *v)
// 原子变量-1
void atomic_dec(atomic_t *v)
//原子变量+1之后判断是否为0,如果为0返回1,否则返回0
int atomic_inc_and_test(atomic_t *v)
//原子变量-1之后判断是否为0,如果为0返回1,否则返回0
int atomic_dec_and_test(atomic_t *v)
示例代码
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
static atomic_t flag;
static struct my_st
{
int major;
int minor;
dev_t dev_num;
struct cdev cdev;
struct class *class;
struct device *dev;
}*my;
static int atomic_open(struct inode *inode,struct file *flip)
{
if(!atomic_dec_and_test(&flag))
{
atomic_inc(&flag);
return -EBUSY;
}
printk("open() %d\r\n",atomic_read(&flag));
return 0;
}
static int atomic_release(struct inode *inode,struct file *flip)
{
atomic_inc(&flag);
printk("release %d \r\n",atomic_read(&flag));
return 0;
}
static const struct file_operations fops =
{
.owner = THIS_MODULE,
.open = atomic_open,
.release = atomic_release,
};
static int __init atomic_init(void)
{
int ret;
printk("atomic_init\r\n");
my=kzalloc(sizeof(struct my_st),GFP_KERNEL);
if(my == NULL)
return -ENOMEM;
atomic_set(&flag,1);
ret = alloc_chrdev_region(&my->dev_num,0,1,"hello_atomic");
if(ret < 0)
return ret;
my->major = MAJOR(my->dev_num);
my->minor = MINOR(my->dev_num);
printk("主设备号:%d 次设备号:%d\r\n",my->major,my->minor);
cdev_init(&my->cdev,&fops);
my->cdev.owner = THIS_MODULE;
ret = cdev_add(&my->cdev,my->dev_num,1);
if(ret < 0)
goto cdev_add_failed;
my->class = class_create(THIS_MODULE,"hello_atomic");
if(IS_ERR(my->class))
{
ret = PTR_ERR(my->class);
goto class_create_failed;
}
my->dev = device_create(my->class,NULL,my->dev_num,NULL,"hello_atomic");
if(IS_ERR(my->dev))
{
ret = PTR_ERR(my->dev);
goto device_create_failed;
}
return 0;
device_create_failed:
class_destroy(my->class);
class_create_failed:
cdev_del(&my->cdev);
cdev_add_failed:
unregister_chrdev_region(my->dev_num,1);
return ret;
}
static void __exit atomic_exit(void)
{
device_destroy(my->class,my->dev_num);
class_destroy(my->class);
cdev_del(&my->cdev);
unregister_chrdev_region(my->dev_num,1);
kfree(my);
printk("atomic_exit\r\n");
}
module_init(atomic_init);
module_exit(atomic_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chen");
MODULE_DESCRIPTION("test type of atomic_t usage");
Makefile
ifneq ($(KERNELRELEASE),)
obj-m:= atomic.o
else
CURRENT_DIR:=$(shell pwd)
KERNEL_DIR:=/lib/modules/$(shell uname -r)/build
ccflags-y:=-std=gnu99 -Wno-declaration-after-statement
all:
$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) modules
clean:
$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_DIR) clean
endif
测试程序
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <error.h>
int main(int argc,char **argv)
{
int fd;
fd = open("/dev/hello_atomic",O_RDWR);
if(fd < 0)
{
perror("");
exit(1);
}
sleep(15);
close(fd);
exit(0);
}
最后编译app.c为app切换到root用户执行app,然后再打开一个终端也执行app就会看到