自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux設(shè)備驅(qū)動(dòng)中的并發(fā)控制

系統(tǒng) Linux
并發(fā)指的是多個(gè)執(zhí)行單元同時(shí)、并行被執(zhí)行,而并發(fā)的執(zhí)行單元對(duì)共享資源的訪問(wèn)則很容易導(dǎo)致競(jìng)態(tài)。

[[208856]]

并發(fā)指的是多個(gè)執(zhí)行單元同時(shí)、并行被執(zhí)行,而并發(fā)的執(zhí)行單元對(duì)共享資源的訪問(wèn)則很容易導(dǎo)致競(jìng)態(tài)。

linux內(nèi)核中主要競(jìng)態(tài)

1.多對(duì)稱處理器的多個(gè)CPU

2.單CPU內(nèi)進(jìn)程與搶占它的進(jìn)程

3.中斷(硬中斷、軟中斷、Tasklet、下半部)與進(jìn)程之間

訪問(wèn)共享內(nèi)存資源的代碼區(qū)稱為“臨界區(qū)”,臨界區(qū)需要被以某種互斥機(jī)制加以保護(hù),中斷屏蔽、原子操作、自旋鎖和信號(hào)量等,是linux設(shè)備驅(qū)動(dòng)中可采用的互斥途徑。

這幾個(gè)互斥的介紹:

1.中斷屏蔽,這個(gè)主要用于單CPU,中斷屏蔽將使得中斷和進(jìn)程之間的并發(fā)不再發(fā)生。

使用方法:

  1. local_irq_disable();//屏蔽中斷 
  2. ... 
  3. ... 
  4. 臨界區(qū) 
  5. ... 
  6. local_irq_enable();//開中斷 

 

由于linux的異步IO、進(jìn)程調(diào)度等很多重要的操作都依賴于中斷,中斷對(duì)于內(nèi)核的運(yùn)行非常重要,在屏蔽中斷期間所有的中斷都無(wú)法處理,因此長(zhǎng)時(shí)間的屏蔽中斷很危險(xiǎn),有可能導(dǎo)致數(shù)據(jù)丟失甚至系統(tǒng)崩潰。所以這個(gè)不作為重點(diǎn)討論。

**********************************************************************************************************************************************************

2.原子操作,原子操作是一系列的不能被打斷的操作。

linux內(nèi)核提供了一系列的函數(shù)來(lái)實(shí)現(xiàn)內(nèi)核中的原子操作,這些函數(shù)分為2類,分別針對(duì)位和整型變量進(jìn)行原子操作。

實(shí)現(xiàn)原子操作的步驟:

1).定義原子變量并設(shè)置變量值

  1. void atomic_set(atomic_t *v , int i); //設(shè)置原子變量值為i 
  2.  
  3. atomic_t v = ATOMIC_INIT(0); //定義原子變量v,初始化為0 

 

2).獲取原子變量的值

  1. atomic_read(atomic_t *v); 

3).原子變量加減操作

  1. void atomic_add(int i,atomic_t *v);//原子變量加i 
  2.  
  3. void atomic_sub(int i ,atomic_t *v);//原子變量減i 

 

4).原子變量自增/自減

  1. void atomic_inc(atomic_t *v);//自增1 
  2.  
  3. void atomic_dec(atomic_t *v);//自減1 

 

5).操作并測(cè)試:對(duì)原子變量執(zhí)行自增、自減后(沒(méi)有加)測(cè)試其是否為0,如果為0返回true,否則返回false。

  1. int atomic_inc_and_test(atomic_t *v); 
  2.  
  3. int atomic_dec_and_test(atomic_t *v); 
  4.  
  5. int atomic_sub_and_test(int i ,atomic_t *v); 

 

6).操作并返回

  1. int atomic_add_return(int i , atomic_t *v); 
  2.  
  3. int atomic_sub_return(int i , atomic_t *v); 
  4.  
  5. int atomic_inc_return(atomic_t * v); 
  6.  
  7. int atomic_dec_return(atomic_t * v); 

 

**********************************************************************************************************************************************************

3.自旋鎖

自旋鎖是一個(gè)忙鎖,它在一個(gè)小的循環(huán)內(nèi)不斷的重復(fù)測(cè)試并設(shè)置的操作。

自旋鎖保護(hù)臨界區(qū)的特點(diǎn):臨界區(qū)要小,并且臨界區(qū)內(nèi)不能有導(dǎo)致睡眠的操作,否則可能引起系統(tǒng)崩潰。自旋鎖可能導(dǎo)致系統(tǒng)死鎖,引發(fā)這個(gè)問(wèn)題最常見(jiàn)的情況是遞歸使用一個(gè)自旋鎖。

自旋鎖的操作步驟:

1).定義自旋鎖

  1. spinlock_t lock; 

2).初始化自旋鎖

  1. spin_lock_init(lock); //這是個(gè)宏,它用于動(dòng)態(tài)初始化自旋鎖lock; 

3).獲得自旋鎖

  1. spin_lock(lock);//該宏用于加鎖,如果能夠立即獲得鎖,它就能馬上返回,否則,他將自旋在那里,直到該自旋鎖的保持者釋放。 
  2.  
  3. spin_trylock(lock);//能夠獲得,則返回真,否則返回假,實(shí)際上是不在原地打轉(zhuǎn)而已。 

 

4).釋放自旋鎖

  1. spin_unlock(lock); 

與上面的兩個(gè)配對(duì)使用。

例子:

  1. spinlock_t lock; 
  2.  
  3. spin_lock_init(&lock); 
  4.  
  5. spin_lock(&lock); //獲取自旋鎖,保護(hù)臨界區(qū)。。。。臨界區(qū) 
  6.  
  7. spin_unlock(&lock);//釋放自旋鎖 

 

自旋鎖不關(guān)心鎖定的臨界區(qū)究竟是如何執(zhí)行的。不管是讀操作還是寫操作,實(shí)際上,對(duì)共享資源進(jìn)行讀取的時(shí)候是應(yīng)該可以允許多個(gè)執(zhí)行單元同時(shí)訪問(wèn)的,那么這樣的話,自旋鎖就有了弊端。于是便衍生出來(lái)一個(gè)讀寫鎖。

它保留了自旋的特性,但在對(duì)操作上面可以允許有多個(gè)單元進(jìn)程同時(shí)操作。當(dāng)然,讀和寫的時(shí)候不能同時(shí)進(jìn)行。

現(xiàn)在又有問(wèn)題了,如果我第一個(gè)進(jìn)程寫共享資源,第二個(gè)進(jìn)程讀的話,一旦寫了,那么就讀不到了,可能寫的東西比較多,但是第二個(gè)進(jìn)程讀很小,那么能不能第一個(gè)進(jìn)程寫的同時(shí),我第二個(gè)進(jìn)程讀呢?

當(dāng)然可以,那么引出了順序鎖的概念。都是一樣的操作。

**********************************************************************************************************************************************************

4.信號(hào)量

是用于保護(hù)臨界區(qū)的一種常用的方法,它的使用與自旋鎖差不多,但是它不在原地打轉(zhuǎn),當(dāng)獲取不到信號(hào)量時(shí)候,進(jìn)程會(huì)進(jìn)入休眠等待狀態(tài)。

主要操作:

1).定義sem信號(hào)量

  1. struct semaphore sem; 

2).初始化信號(hào)量

  1. void sema_init(struct semaphore *sem, int val); 

初始化信號(hào)量,并設(shè)置sem的值為val

初始化的時(shí)候還可以這樣用,init_MUTEX(sem),這是個(gè)宏 #define init_MUTEX(sem) sema_init(sem , 1)

init_MUTEX_LOCKED(sem),這是個(gè)宏 #define init_MUTEX_LOCKED(sem) sema_init(sem , 0)

3).獲得信號(hào)量

  1. void down(struct semaphore * sem); 

該函數(shù)用于獲得信號(hào)量sem,他會(huì)導(dǎo)致睡眠,所以不能在中斷中使用。

  1. int down_interruptible(struct semaphore* sem); 

與上面功能類似,因?yàn)閐own進(jìn)入睡眠狀態(tài)的進(jìn)程不能被信號(hào)打斷,而它能被信號(hào)打斷,信號(hào)也會(huì)導(dǎo)致該函數(shù)返回。

  1. int down_trylock(struct semaphore * sem); 

4).釋放信號(hào)量

  1. void up(struct semaphore * sem); 

該函數(shù)用于釋放信號(hào)量,同時(shí)喚醒等待者。

信號(hào)量一般這樣使用:

  1. DECLARE_MUTEX(sem); 
  2.  
  3. down(&sem); 
  4.  
  5. .....臨界區(qū) 
  6.  
  7. up(&sem); 

 

linux自旋鎖和信號(hào)量采用的“獲取鎖-訪問(wèn)臨界區(qū)-釋放鎖”的方式。

*************************************************************************************************************************

5.互斥體

互斥體和信號(hào)量基本上差不多。不介紹了。

總結(jié):

并發(fā)和競(jìng)態(tài)廣泛存在,這幾個(gè)機(jī)制是解決問(wèn)題的好方法,中斷屏蔽很少單獨(dú)使用,原子操作只能針對(duì)整數(shù)進(jìn)行,因此,自旋鎖和信號(hào)量應(yīng)用最為廣泛。

自旋鎖會(huì)導(dǎo)致死循環(huán),鎖定期間不允許阻塞,因此要求鎖定的臨界區(qū)要小。信號(hào)量允許臨界區(qū)阻塞,可以適用于臨界區(qū)較大的情況。讀寫自旋鎖和讀寫信號(hào)量是放寬了條件的自旋鎖和信號(hào)量,他們?cè)试S多個(gè)進(jìn)程并發(fā)的讀取共享空間。

一個(gè)fifo的綜合例子

  1. /*====================================================================== 
  2.     A globalfifo driver as an example of char device drivers   
  3.     This example is to introduce poll,blocking and non-blocking access 
  4.        
  5.     The initial developer of the original code is Baohua Song 
  6.     <author@linuxdriver.cn>. All Rights Reserved. 
  7. ======================================================================*/#include <linux/module.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/cdev.h>#include <asm/io.h>#include <asm/system.h>#include <asm/uaccess.h>#include <linux/poll.h>#include <linux/time.h>#include <linux/timer.h>#include <linux/kernel.h>#include <linux/spinlock.h>#include <linux/interrupt.h>#define GLOBALFIFO_SIZE 0x1000 /*全局fifo最大4K字節(jié)*/#define FIFO_CLEAR 0x1  /*清0全局內(nèi)存的長(zhǎng)度*/#define GLOBALFIFO_MAJOR 250    /*預(yù)設(shè)的globalfifo的主設(shè)備號(hào)*/static int globalfifo_major = GLOBALFIFO_MAJOR;/*globalfifo設(shè)備結(jié)構(gòu)體*/struct globalfifo_dev                                      
  8. {                                                         
  9.   struct cdev cdev; /*cdev結(jié)構(gòu)體*/                        
  10.   unsigned int current_len;    /*fifo有效數(shù)據(jù)長(zhǎng)度*/ 
  11.   unsigned char mem[GLOBALFIFO_SIZE]; /*全局內(nèi)存*/         
  12.   struct semaphore sem; /*并發(fā)控制用的信號(hào)量*/            
  13.   wait_queue_head_t r_wait; /*阻塞讀用的等待隊(duì)列頭*/      
  14.   wait_queue_head_t w_wait; /*阻塞寫用的等待隊(duì)列頭*/      
  15.   struct tasklet_struct tlet; 
  16. };struct globalfifo_dev *globalfifo_devp; /*設(shè)備結(jié)構(gòu)體指針*//*文件打開函數(shù)*/int globalfifo_open(struct inode *inode, struct file *filp) 
  17. {  /*將設(shè)備結(jié)構(gòu)體指針賦值給文件私有數(shù)據(jù)指針*/ 
  18.   filp->private_data = globalfifo_devp;  return 0; 
  19. }/*文件釋放函數(shù)*/int globalfifo_release(struct inode *inode, struct file *filp) 
  20. {  return 0; 
  21. }/* ioctl設(shè)備控制函數(shù) */static int globalfifo_ioctl(struct inode *inodep, struct file *filp, unsigned  int cmd, unsigned long arg) 
  22. {  struct globalfifo_dev *dev = filp->private_data;/*獲得設(shè)備結(jié)構(gòu)體指針*/ 
  23.  
  24.   switch (cmd) 
  25.   {    case FIFO_CLEAR: 
  26.      down(&dev->sem); //獲得信號(hào)量      
  27.       dev->current_len = 0; 
  28.       memset(dev->mem,0,GLOBALFIFO_SIZE); 
  29.       up(&dev->sem); //釋放信號(hào)量          
  30.       printk(KERN_INFO "globalfifo is set to zero\n");       
  31.       break;    default:      return  - EINVAL; 
  32.   }  return 0; 
  33. }static unsigned int globalfifo_poll(struct file *filp, poll_table *wait) 
  34.   unsigned int mask = 0;  struct globalfifo_dev *dev = filp->private_data; /*獲得設(shè)備結(jié)構(gòu)體指針*/ 
  35.    
  36.   down(&dev->sem); 
  37.    
  38.   poll_wait(filp, &dev->r_wait, wait); 
  39.   poll_wait(filp, &dev->w_wait, wait);   
  40.   /*fifo非空*/ 
  41.   if (dev->current_len != 0) 
  42.   { 
  43.     mask |= POLLIN | POLLRDNORM; /*標(biāo)示數(shù)據(jù)可獲得*/ 
  44.   }  /*fifo非滿*/ 
  45.   if (dev->current_len != GLOBALFIFO_SIZE) 
  46.   { 
  47.     mask |= POLLOUT | POLLWRNORM; /*標(biāo)示數(shù)據(jù)可寫入*/ 
  48.   } 
  49.       
  50.   up(&dev->sem);  return mask; 
  51. }/*globalfifo讀函數(shù)*/static ssize_t globalfifo_read(struct file *filp, char __user *buf, size_t count
  52.   loff_t *ppos) 
  53. {  int ret;  struct globalfifo_dev *dev = filp->private_data; //獲得設(shè)備結(jié)構(gòu)體指針 
  54.   DECLARE_WAITQUEUE(wait, current); //定義等待隊(duì)列 
  55.   down(&dev->sem); //獲得信號(hào)量 
  56.   add_wait_queue(&dev->r_wait, &wait); //進(jìn)入讀等待隊(duì)列頭 
  57.  
  58.   /* 等待FIFO非空 */ 
  59.   if (dev->current_len == 0) 
  60.   {    if (filp->f_flags &O_NONBLOCK) 
  61.     { 
  62.       ret =  - EAGAIN;      goto out
  63.     }  
  64.     __set_current_state(TASK_INTERRUPTIBLE); //改變進(jìn)程狀態(tài)為睡眠 
  65.     up(&dev->sem); 
  66.  
  67.     schedule(); //調(diào)度其他進(jìn)程執(zhí)行 
  68.     if (signal_pending(current))    //如果是因?yàn)樾盘?hào)喚醒    { 
  69.       ret =  - ERESTARTSYS;      goto out2; 
  70.     } 
  71.  
  72.     down(&dev->sem); 
  73.   }  /* 拷貝到用戶空間 */ 
  74.   if (count > dev->current_len) 
  75.     count = dev->current_len;  if (copy_to_user(buf, dev->mem, count)) 
  76.   { 
  77.     ret =  - EFAULT;    goto out
  78.   }  else 
  79.   { 
  80.     memcpy(dev->mem, dev->mem + count, dev->current_len - count); //fifo數(shù)據(jù)前移 
  81.     dev->current_len -= count; //有效數(shù)據(jù)長(zhǎng)度減少 
  82.     printk(KERN_INFO "read %d bytes(s),current_len:%d\n"count, dev->current_len); 
  83.       
  84.     wake_up_interruptible(&dev->w_wait); //喚醒寫等待隊(duì)列     
  85.     ret = count
  86.   }  out: up(&dev->sem); //釋放信號(hào)量 
  87.   out2:remove_wait_queue(&dev->w_wait, &wait); //從附屬的等待隊(duì)列頭移除  set_current_state(TASK_RUNNING);  return ret; 
  88. }/*globalfifo寫操作*/static ssize_t globalfifo_write(struct file *filp, const char __user *buf, 
  89.   size_t count, loff_t *ppos) 
  90. {  struct globalfifo_dev *dev = filp->private_data; //獲得設(shè)備結(jié)構(gòu)體指針 
  91.   int ret; 
  92.   DECLARE_WAITQUEUE(wait, current); //定義等待隊(duì)列 
  93.   down(&dev->sem); //獲取信號(hào)量 
  94.   add_wait_queue(&dev->w_wait, &wait); //進(jìn)入寫等待隊(duì)列頭 
  95.  
  96.   /* 等待FIFO非滿 */ 
  97.   if (dev->current_len == GLOBALFIFO_SIZE) 
  98.   {    if (filp->f_flags &O_NONBLOCK)    //如果是非阻塞訪問(wèn)    { 
  99.       ret =  - EAGAIN;      goto out
  100.     }  
  101.     __set_current_state(TASK_INTERRUPTIBLE); //改變進(jìn)程狀態(tài)為睡眠 
  102.     up(&dev->sem); 
  103.  
  104.     schedule(); //調(diào)度其他進(jìn)程執(zhí)行 
  105.     if (signal_pending(current))    //如果是因?yàn)樾盘?hào)喚醒    { 
  106.       ret =  - ERESTARTSYS;      goto out2; 
  107.     } 
  108.  
  109.     down(&dev->sem); //獲得信號(hào)量  }  /*從用戶空間拷貝到內(nèi)核空間*/ 
  110.   if (count > GLOBALFIFO_SIZE - dev->current_len) 
  111.     count = GLOBALFIFO_SIZE - dev->current_len;  if (copy_from_user(dev->mem + dev->current_len, buf, count)) 
  112.   { 
  113.     ret =  - EFAULT;    goto out
  114.   }  else 
  115.   { 
  116.     dev->current_len += count
  117.     printk(KERN_INFO "written %d bytes(s),current_len:%d\n"count, dev      ->current_len); 
  118.  
  119.     wake_up_interruptible(&dev->r_wait); //喚醒讀等待隊(duì)列     
  120.     ret = count
  121.   } 
  122.  
  123.  
  124. tasklet_schedule(&dev->tlet); 
  125. printk("in write jiffies=%ld\n",jiffies);  out: up(&dev->sem); //釋放信號(hào)量 
  126.   out2:remove_wait_queue(&dev->w_wait, &wait); //從附屬的等待隊(duì)列頭移除  set_current_state(TASK_RUNNING);  return ret; 
  127. }/*文件操作結(jié)構(gòu)體*/static const struct file_operations globalfifo_fops ={ 
  128.   .owner = THIS_MODULE, 
  129.   .read = globalfifo_read, 
  130.   .write = globalfifo_write, 
  131.   .ioctl = globalfifo_ioctl, 
  132.   .poll = globalfifo_poll, 
  133.   .open = globalfifo_open, 
  134.   .release = globalfifo_release, 
  135. };/*初始化并注冊(cè)cdev*/static void globalfifo_setup_cdev(struct globalfifo_dev *dev, int index
  136. {  int err, devno = MKDEV(globalfifo_major, index); 
  137.  
  138.   cdev_init(&dev->cdev, &globalfifo_fops); 
  139.   dev->cdev.owner = THIS_MODULE; 
  140.   dev->cdev.ops = &globalfifo_fops; 
  141.   err = cdev_add(&dev->cdev, devno, 1);  if (err) 
  142.     printk(KERN_NOTICE "Error %d adding LED%d", err, index); 
  143. }void jit_tasklet_fn(unsigned long arg) 
  144.  printk("in jit_tasklet_fn  jiffies=%ld\n",jiffies); 
  145. }/*設(shè)備驅(qū)動(dòng)模塊加載函數(shù)*/int globalfifo_init(void) 
  146. {  int ret; 
  147.   dev_t devno = MKDEV(globalfifo_major, 0);  /* 申請(qǐng)?jiān)O(shè)備號(hào)*/ 
  148.   if (globalfifo_major) 
  149.     ret = register_chrdev_region(devno, 1, "globalfifo");  else  /* 動(dòng)態(tài)申請(qǐng)?jiān)O(shè)備號(hào) */ 
  150.  
  151.   { 
  152.     ret = alloc_chrdev_region(&devno, 0, 1, "globalfifo"); 
  153.     globalfifo_major = MAJOR(devno); 
  154.   }  if (ret < 0)    return ret;  /* 動(dòng)態(tài)申請(qǐng)?jiān)O(shè)備結(jié)構(gòu)體的內(nèi)存*/ 
  155.   globalfifo_devp = kmalloc(sizeof(struct globalfifo_dev), GFP_KERNEL);  if (!globalfifo_devp)    /*申請(qǐng)失敗*/ 
  156.   { 
  157.     ret =  - ENOMEM;    goto fail_malloc; 
  158.   } 
  159.  
  160.   memset(globalfifo_devp, 0, sizeof(struct globalfifo_dev)); 
  161.  
  162.   globalfifo_setup_cdev(globalfifo_devp, 0); 
  163.  
  164.   init_MUTEX(&globalfifo_devp->sem);   /*初始化信號(hào)量*/ 
  165.   init_waitqueue_head(&globalfifo_devp->r_wait); /*初始化讀等待隊(duì)列頭*/ 
  166.   init_waitqueue_head(&globalfifo_devp->w_wait); /*初始化寫等待隊(duì)列頭*/ 
  167.  /* register the tasklet */ 
  168.  tasklet_init(&globalfifo_devp->tlet, jit_tasklet_fn, (unsigned long)globalfifo_devp);  return 0; 
  169.  
  170.   fail_malloc: unregister_chrdev_region(devno, 1);  return ret; 
  171. }/*模塊卸載函數(shù)*/void globalfifo_exit(void) 
  172.   cdev_del(&globalfifo_devp->cdev);   /*注銷cdev*/ 
  173.   kfree(globalfifo_devp);     /*釋放設(shè)備結(jié)構(gòu)體內(nèi)存*/ 
  174.   unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1); /*釋放設(shè)備號(hào)*/} 
  175.  
  176. MODULE_AUTHOR("Song Baohua"); 
  177. MODULE_LICENSE("Dual BSD/GPL"); 
  178.  
  179. module_param(globalfifo_major, int, S_IRUGO); 
  180.  
  181. module_init(globalfifo_init); 
  182. module_exit(globalfifo_exit); 

 

責(zé)任編輯:龐桂玉 來(lái)源: 嵌入式Linux中文站
相關(guān)推薦

2017-02-28 17:46:15

Linux驅(qū)動(dòng)技術(shù)并發(fā)控制

2023-05-15 08:58:41

塊設(shè)備驅(qū)動(dòng)Linux

2023-05-12 07:27:24

Linux內(nèi)核網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)

2020-12-03 08:59:06

Linux設(shè)備驅(qū)動(dòng)

2017-02-10 15:32:47

2021-11-29 07:55:45

Linux GPIO Linux 系統(tǒng)

2017-11-16 14:46:58

Linuxplatform總線驅(qū)動(dòng)設(shè)備

2009-02-09 10:06:03

并發(fā)控制Web應(yīng)用悲觀鎖

2022-05-10 08:49:46

設(shè)備驅(qū)動(dòng)Linux

2021-04-07 06:00:18

JavaScript 前端并發(fā)控制

2009-12-23 13:17:36

Linux設(shè)備驅(qū)動(dòng)

2011-01-10 18:21:38

linux編寫程序

2016-12-15 14:55:31

Linux定時(shí)延時(shí)

2021-04-12 12:00:13

Linux運(yùn)維Linux系統(tǒng)

2009-12-07 09:39:04

Linux設(shè)備驅(qū)動(dòng)硬件通信

2022-05-26 00:48:55

Linux內(nèi)核硬件

2017-08-21 10:56:55

MySQL并發(fā)控制

2010-05-07 10:55:37

Windows 7驅(qū)動(dòng)設(shè)備

2010-05-10 15:53:24

Unix系統(tǒng)

2022-01-17 11:50:38

Linux CPULinux 系統(tǒng)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)