原子变量和自旋锁
Posted 爱新觉罗玄烨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原子变量和自旋锁相关的知识,希望对你有一定的参考价值。
这一章节想要大家学习的就是在多进程或者多线程下:如何不冲突的访问同一个文件或者是同一段共享资源:
有如下几个机制需要大家来学习:
原子变量:
普通变量count++:看起来是一句话:实际是三个步骤:第一:首先要把这个变量在内存当中取到CPU:第二:把这个变量进行++;第三:把这个变量的值送回内存:所以这是分了三个步骤:每一个步骤都有可能被打断,所以对这个值的操作不原子.
原子:即一气呵成:一旦成功,则所有过程都成功,一旦失败,所有过程都失败.所以原子变量并不是不可被打断的.
原子变量count++:也是分成三个步骤:前两个步骤与普通变量一样:第三个步骤:在进行往内存写的时候,会检测是否在我取出之后这个变量被重新写入过,如果被写入过,则重新把这个变量读取出来进行++,然后在写入.(这个功能实现的方式是在下面这个atomic.h中的一段内嵌汇编实现的)
vim arch/arm/include/asm/atomic.h这个头文件是原子变量相关的代码,下面列出一个例子
39 static inline void atomic_add(int i, atomic_t *v) 40 { 41 unsigned long tmp; 42 int result; 43 44 __asm__ __volatile__("@ atomic_add\n" 45 "1: ldrex %0, [%3]\n" 46 " add %0, %0, %4\n" 47 " strex %1, %0, [%3]\n" 48 " teq %1, #0\n" 49 " bne 1b" 50 : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) 51 : "r" (&v->counter), "Ir" (i) 52 : "cc"); 53 }
插曲:中断除了正在运行的指令不可以打断,其他任何过程都可以打断:在不可抢占的内核的一段代码:在之前屏蔽中断,操作之后再打开中断,这样中间的一段代码是不可能被其他任何情况打断了.
以上就是原子变量理解过程的一些原理讲解:
下面我们来看下如何运用原子变量:(与自旋锁在同一个代码中)
下面几个机制来限制共享资源的访问:
自旋锁:
spinlock_t
使用原则:无论下面那种情况:在进行共享资源的操作时,都要使用自旋锁.因为方便移植.
自旋锁:即一直等待,强不到锁就一直等待(忙等),占着CPU不放:举个例子:你比较内急,但是洗手间有人在使用,你就一直在门口等待.什么事都干不了.哈哈!
自旋锁不睡眠:所以可以在中断上下文使用,当然也可以在进程上下文:如果一直强不到锁,那么程序的效率将会很低.
注意:
1):自死锁:
2)ABBA死锁:两个进程一人抢到一把锁,但是要求抢到两把锁才能进行操作,所以两个进程一直等待对方释放,因此就会出现这样的锁:解决方法就是设定规则:必须先抢到A在强B,才能进行操作
3)带着锁不能睡眠.
4)在函数或者程序返回之前一定要解锁:
5)自旋锁是建议性锁,你不嫁锁当然也可以操作....哈哈..气人不....只是资源让你给破坏了
1.如果是单核CPU,且内核不支持抢占.自旋锁无效:
2.单核CPU,内核支持抢占:加锁==禁止抢占:解锁==使能抢占:这种情况,也可以直接用动态内核抢占方式.
3.多核CPU
自旋锁例子:
1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/sched.h> 4 #include <linux/cdev.h> 5 #include <linux/gpio.h> 6 #include <linux/kdev_t.h> 7 #include <linux/slab.h> 8 #include <linux/fs.h> 9 #include <asm/uaccess.h> 10 #include <asm/atomic.h> 11 #include <linux/spinlock.h> 12 #include <linux/interrupt.h> 13 #include <mach/gpio.h> 14 15 struct mydev_st { 16 char buf[256]; 17 dev_t no; 18 struct cdev dev; 19 20 atomic_t count; 21 22 spinlock_t lock; 23 24 int irq; 25 }; 26 // /dev/test/mydev 27 int my_open(struct inode *no, struct file *fp) 28 { 29 struct mydev_st *m; 30 31 m = container_of(no->i_cdev, struct mydev_st, dev); 32 memset(m->buf, 0, 256); 33 //m->count.couner++; 34 atomic_add(1, &m->count); 35 fp->private_data = m; 36 37 //printk("%s\n", __FUNCTION__); 38 return 0; 39 } 40 41 int my_close(struct inode *no, struct file *fp) 42 { 43 struct mydev_st *m; 44 45 m = container_of(no->i_cdev, struct mydev_st, dev); 46 atomic_sub(1, &m->count); 47 48 //printk("%s\n", __FUNCTION__); 49 return 0; 50 } 51 52 ssize_t my_read(struct file *fp, char __user *buffer, size_t count, loff_t *off) 53 { 54 struct mydev_st *m; 55 int ret; 56 unsigned long flags; 57 58 m = fp->private_data; 59 60 count = min((int)count, 256); 61 62 //spin_lock(&m->lock); 63 spin_lock_irqsave(&m->lock, flags); 64 ret = copy_to_user(buffer, m->buf, count); 65 if (ret) { 66 ret = -EFAULT; 67 //spin_unlock(&m->lock); 68 spin_unlock_irqrestore(&m->lock, flags); 69 goto copy_error; 70 } 71 72 // spin_unlock(&m->lock); 73 spin_unlock_irqrestore(&m->lock, flags); 74 //printk("%s\n", __FUNCTION__); 75 return count; 76 copy_error: 77 return ret; 78 } 79 80 ssize_t my_write(struct file *fp, const char __user *buffer, size_t count, loff_t *off) 81 { 82 //printk("%s\n", __FUNCTION__); 83 84 int ret; 85 unsigned long flags; 86 87 struct mydev_st *m; 88 89 m = fp->private_data; 90 91 count = min((int)count, 256); 92 93 //spin_lock(&m->lock); 94 //防止中断打断:加锁并禁止中断 95 spin_lock_irqsave(&m->lock, flags); 96 ret = copy_from_user(m->buf, buffer, count); 97 if (ret) { 98 ret = -EFAULT; 99 //spin_unlock(&m->lock); 100 spin_unlock_irqrestore(&m->lock, flags); 101 goto copy_error; 102 } 103 //解锁并使能中断 104 spin_unlock_irqrestore(&m->lock, flags); 105 //spin_unlock(&m->lock); 106 107 return count; 108 copy_error: 109 return ret; 110 } 111 112 long my_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) 113 { 114 printk("%s %u %ld\n", __FUNCTION__, cmd, arg); 115 116 return 0; 117 } 118 119 irqreturn_t irq_handler(int irq, void *data) 120 { 121 struct mydev_st *m; 122 123 m = data; 124 125 //spin_lock(&m->lock); 126 127 memcpy(m->buf, "nihao", 5); 128 129 //spin_unlock(&m->lock); 130 131 return IRQ_HANDLED; 132 } 133 134 struct file_operations my_ops = { 135 .open = my_open, 136 .release = my_close, 137 .write = my_write, 138 .read = my_read, 139 .unlocked_ioctl = my_ioctl, 140 }; 141 142 struct mydev_st *mydev; 143 144 //当模块安装的时候执行 145 static __init int test_init(void) 146 { 147 int ret; 148 149 mydev = kzalloc(sizeof(*mydev), GFP_KERNEL); 150 if (!mydev) { 151 ret = -ENOMEM; 152 goto alloc_dev_error; 153 } 154 155 mydev->count.counter = 0; 156 spin_lock_init(&mydev->lock); 157 158 ret = alloc_chrdev_region(&mydev->no, 1, 1, "mydev"); 159 if (ret < 0) { 160 goto alloc_no_error; 161 } 162 163 cdev_init(&mydev->dev, &my_ops); 164 ret = cdev_add(&mydev->dev, mydev->no, 1); 165 if (ret < 0) { 166 goto cdev_add_error; 167 } 168 169 mydev->irq = gpio_to_irq(EXYNOS4_GPX3(2)); 170 ret = request_irq(mydev->irq, irq_handler, IRQF_TRIGGER_FALLING, "haha", mydev); 171 /* if errer */ 172 173 printk("major=%d minor=%d\n", MAJOR(mydev->no), MINOR(mydev->no)); 174 175 return 0; 176 cdev_add_error: 177 unregister_chrdev_region(mydev->no, 1); 178 alloc_no_error: 179 kfree(mydev); 180 alloc_dev_error: 181 return ret; 182 } 183 184 //当模块卸载的时候执行 185 static __exit void test_exit(void) 186 { 187 free_irq(mydev->irq, mydev); 188 cdev_del(&mydev->dev); 189 unregister_chrdev_region(mydev->no, 1); 190 kfree(mydev); 191 } 192 193 module_init(test_init); 194 module_exit(test_exit); 195 196 MODULE_LICENSE("GPL");
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <sys/types.h> 4 #include <fcntl.h> 5 #include <string.h> 6 #include <sys/ioctl.h> 7 8 #define DEV "/dev/test/mydev" 9 10 int main(void) 11 { 12 int fd; 13 char buf[20]; 14 int ret; 15 16 fd = open(DEV, O_RDWR); 17 if (fd < 0) { 18 perror("open"); 19 exit(1); 20 } 21 22 write(fd, "123", 3); 23 ret = read(fd, buf, sizeof(buf)); 24 write(1, buf, ret); 25 26 ioctl(fd, 1, 1); 27 28 close(fd); 29 30 return 0; 31 }
1 LINUX_SRC :=/var/ftp/opt/linux-3.5 2 3 obj-m += module.o 4 module-objs = cdev_test2.o 5 6 #obj-m += module_test1.o 7 all: 8 make -C $(LINUX_SRC) M=`pwd` modules 9 clean: 10 make -C $(LINUX_SRC) M=`pwd` modules clean
信号量:
互斥量:
完成量:
seq锁:
以上是关于原子变量和自旋锁的主要内容,如果未能解决你的问题,请参考以下文章