這一章節想要你們學習的就是在多進程或者多線程下:如何不衝突的訪問同一個文件或者是同一段共享資源:node
有以下幾個機制須要你們來學習:linux
原子變量:vim
普通變量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 }
插曲:中斷除了正在運行的指令不能夠打斷,其餘任何過程均可以打斷:在不可搶佔的內核的一段代碼:在以前屏蔽中斷,操做以後再打開中斷,這樣中間的一段代碼是不可能被其餘任何狀況打斷了.學習
以上就是原子變量理解過程的一些原理講解:atom
下面咱們來看下如何運用原子變量:(與自旋鎖在同一個代碼中)spa
下面幾個機制來限制共享資源的訪問:線程
自旋鎖:include/linux/spinlock.h
spinlock_t
使用原則:不管下面那種狀況:在進行共享資源的操做時,都要使用自旋鎖.由於方便移植.
自旋鎖:即一直等待,強不到鎖就一直等待(忙等),佔着CPU不放:舉個例子:你比較內急,可是洗手間有人在使用,你就一直在門口等待.什麼事都幹不了.哈哈!
自旋鎖不睡眠:因此能夠在中斷上下文使用,固然也能夠在進程上下文:若是一直強不到鎖,那麼程序的效率將會很低.
注意:
1):自死鎖:(即:本身加了一把鎖,而後又要加這把鎖,致使本身等待本身釋放,這樣就產生了自死鎖)。
2)ABBA死鎖:兩個進程一人搶到一把鎖,可是要求搶到兩把鎖才能進行操做,因此兩個進程一直等待對方釋放,所以就會出現這樣的鎖:解決方法就是設定規則:必須先搶到A在強B,才能進行操做
3)帶着鎖不能睡眠.
4)在函數或者程序返回以前必定要解鎖:
5)自旋鎖是建議性鎖,你不加鎖固然也能夠操做....哈哈..氣人不....只是資源讓你給破壞了
1.若是是單核CPU,且內核不支持搶佔.自旋鎖無效:
2.單核CPU,內核支持搶佔:加鎖==禁止搶佔:解鎖==使能搶佔:這種狀況,也能夠直接用動態內核搶佔方式.
3.多核CPU:多核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
信號量: include/linux/semaphore.h
信號量:也是內核處理併發訪問共享資源的一種方式。
信號量的特色:獲取不到信號量,則睡眠等待,獲取信號量的函數有
down():睡眠不可被打斷
down_interruptiabl():睡眠能夠被中斷打斷
down_killable():可以殺死進程的信號,能夠打斷睡眠。
down_trylock():試圖獲取信號量,若是獲取不到,也不睡眠,會出錯返回。
up():釋放信號量:
sema_init():初始化信號量
struct semaphore :定義信號量
互斥量:include/linux/mutex.h
通常有了互斥量,基本不使用信號量了。因此互斥量相對用的多一些。
struct mutex
mutex_init
mutex_lock
mutex_trylock
mutex_lock_interruptible
mutex_lock_killable
mutex_unlock
意思同上:
讀寫鎖:include/linux/rwlock.h
若是加了讀鎖,能夠重複加,
加寫鎖的條件:既沒有讀者也沒有寫者。
加了寫鎖狀況下:不能再加讀鎖,也不能在加寫鎖。
只加了讀鎖的狀況下:仍是能夠加讀鎖的。不能夠加寫鎖
餓死寫者:指的是:寫者想要寫,就必須等待沒有讀者的狀況下,可是讀者有肯能源源不斷的在讀,多個讀者,那麼就會產生寫着一直等待。這中狀況適用於讀者居多,很好寫的狀況。
使用的函數:
rwlock_t
rwlock_init
read_lock
讀寫信號量:include/linux/rwsemaphore.h
原理同讀寫鎖:
寫這優先:seq鎖
多個寫着不可共存,
多個讀者能夠共存
有讀者時,寫着可寫
讀者每次讀都要檢測寫着是否來過,do {read_seq 。。。。。} while(read_tryseq)
其中read_seq是讀出來偶數才繼續執行,不然循環read_seq,讀完出來時判斷是否有寫着來過,即再次讀出來的數值變成奇數,說明寫着來過,從新讀取。