最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解析Linux內(nèi)核的基本的模塊管理與時間管理操作

 更新時間:2016年02月24日 14:24:01   作者:喝醉的毛毛蟲  
這篇文章主要介紹了Linux內(nèi)核的基本的模塊管理與時間管理操作,包括模塊加載卸載函數(shù)的使用和定時器的用法等知識,需要的朋友可以參考下

內(nèi)核模塊管理
Linux設(shè)備驅(qū)動會以內(nèi)核模塊的形式出現(xiàn),因此學(xué)會編寫Linux內(nèi)核模塊編程是學(xué)習(xí)linux設(shè)備驅(qū)動的先決條件。

Linux內(nèi)核的整體結(jié)構(gòu)非常龐大,其包含的組件非常多。我們把需要的功能都編譯到linux內(nèi)核,以模塊方式擴(kuò)展內(nèi)核功能。

先來看下最簡單的內(nèi)核模塊

#include <linux/init.h> 
#include <linux/module.h> 
 
 
static int __init hello_init(void) 
{ 
    printk(KERN_ALERT "Hello world! %s, %d\n", __FILE__, __LINE__); 
    return 0; 
} 
 
static void __exit hello_exit(void) 
{ 
 
    printk(KERN_ALERT "Hello world! %s, %d\n", __FILE__, __LINE__); 
} 
 
module_init(hello_init); 
module_exit(hello_exit); 
 
MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("Mikcy Liu"); 
MODULE_DESCRIPTION("A simple Module"); 
MODULE_ALIAS("a simple module"); 

頭文件init.h包含了宏_init和_exit,它們允許釋放內(nèi)核占用的內(nèi)存。
module_init()和hello_exit()是模塊編程中最基本也是必須的兩個函數(shù)。
module_init()是驅(qū)動程序初始化的入口點。
hello_exit是模塊的退出和清理函數(shù)。此處可以做所有終止該驅(qū)動程序時相關(guān)的清理工作。

內(nèi)核模塊中用于輸出的函數(shù)式內(nèi)核空間的printk()而非用戶空間的printf(),printk()的用法和printf()相似,但前者可定義輸出級別。printk()可作為一種最基本的內(nèi)核調(diào)試手段

前者可以定義輸出級別,在 <內(nèi)核目錄>/include/linux/kernel.h中

#define KERN_EMERG   "<0>"  /* system is unusable          */ 
#define KERN_ALERT   "<1>"  /* action must be taken immediately   */ 
#define KERN_CRIT    "<2>"  /* critical conditions         */ 
#define KERN_ERR    "<3>"  /* error conditions           */ 
#define KERN_WARNING  "<4>"  /* warning conditions          */ 
#define KERN_NOTICE   "<5>"  /* normal but significant condition   */ 
#define KERN_INFO    "<6>"  /* informational            */ 
#define KERN_DEBUG   "<7>"  /* debug-level messages         */ 

未設(shè)定級別的,在<內(nèi)核目錄>/kernel/printk.c中定義

/* printk's without a loglevel use this.. */ 
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */ 
 #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */ 

只有當(dāng)printk打印信息時的loglevel小于DEFAULT_CONSOLE_LOGLEVEL的值(優(yōu)先級高于console loglevel),這些信息才會被打印到console上。

模塊聲明與描述

  •    在linux模塊中,我們可以使用
  •    MODULE_LICENSE(license)   //定義模塊的license,一般為GPL,或相關(guān)公司的license
  •    MODULE_AUTHOR             //模塊的作者
  •    MODULE_DESCRIPTION        //對模塊程序的描述,string
  •    MODULE_VERSION            //版本
  •    MODULE_DEVICE_TABLE       //模塊程序所支持的設(shè)備,string
  •    MODULE_ALIAS              //別名
  •    MODULE_PARM(var,type)     //模塊參數(shù)

模塊編譯
首先看看Makefile文件:

obj-m := hello.o 
KERNEL_BUILD := /lib/modules/$(shell uname -r)/build 
all: 
    make -C $(KERNEL_BUILD) M=$(shell pwd) modules 
clean: 
    -rm -rf *.o *.ko *.mod.c .*.cmd *.order *.symvers .tmpversions 
KERNELBUILD :=/lib/modules/$(shell uname -r)/

build是編譯內(nèi)核模塊需要的Makefile的路徑,Ubuntu下是/lib/modules/2.6.31-14-generic/build

如果是Arm平臺的開發(fā)板,則-C選項指定的位置(即內(nèi)核源代碼目錄),其中保存有內(nèi)核的頂層Makefile文件.

make -C $(KERNEL_BUILD) M=$(shell pwd) modules 編譯內(nèi)核模塊。-C 將工作目錄轉(zhuǎn)到KERNEL_BUILD,調(diào)用該目錄下的Makefile,并向這個Makefile傳遞參數(shù)M的值是$(shell pwd) modules。

M=選項讓該makefile在構(gòu)造modules目標(biāo)之前返回到模塊源代碼目錄。然后modules目標(biāo)指向obj-m變量中設(shè)定的模塊

執(zhí)行make命令開始編譯模塊,生成hello.ko,執(zhí)行make clean可清除編譯產(chǎn)生的文件。

1、添加模塊

   insmod hello.ko

2、查看模塊

  lsmod | grep hello

   lsmod命令實際上讀取并分析/proc/modules文件,也可以cat /proc/modules文件

   在模塊所在目錄下執(zhí)行

    modinfo  hello.ko可以查看模塊信息,如下所示

filename:    hello.ko
alias:     a simple module
description:  A simple Module
author:     Mikcy Liu
license:    GPL
srcversion:   875C95631F4F336BBD4216C
depends:    
vermagic:    3.5.0-17-generic SMP mod_unload modversions 686

3、刪除模塊

 rmmod hello


模塊加載函數(shù)

Linux內(nèi)核模塊加載函數(shù)一般以__init標(biāo)識聲明,典型的模塊加載函數(shù)的形式如下:

static int __init initialization_function(void) { 
   //初始化代碼  
}  
module_init(initialization_function); 

    模塊加載函數(shù)必須以“module_init(函數(shù)名)”的形式指定。它返回整形值,若初始化成功,應(yīng)返回0。而在初始化失敗時。應(yīng)該返回錯誤編碼。

    在linux內(nèi)核里,錯誤編碼是一個負(fù)值,在<linux/errno.h>中定義,包含-ENODEV、-ENOMEM之類的符號值。返回相應(yīng)的錯誤編碼是種非常好的習(xí)慣,因為只有這樣,用戶程序才可以利用perror等方法把它們轉(zhuǎn)換成有意義的錯誤信息字符串。

    在linux2.6內(nèi)核中,所有標(biāo)識為__init的函數(shù)在連接的時候都會放在.init.text(這是module_init宏在目標(biāo)代碼中增加的一個特殊區(qū)段,用于說明內(nèi)核初始化函數(shù)的所在位置)這個區(qū)段中,此外,所有的__init函數(shù)在區(qū)段.initcall.init中還保存著一份函數(shù)指針,在初始化時內(nèi)核會通過這些函數(shù)指針調(diào)用這些__init函數(shù),并在初始化完成后釋放init區(qū)段(包括.init.text和.initcall.init等)。所以大家應(yīng)注意不要在結(jié)束初始化后仍要使用的函數(shù)上使用這個標(biāo)記。

模塊卸載函數(shù)

Linux內(nèi)核卸載模塊函數(shù)一般以__exit標(biāo)識聲明,典型的模塊卸載函數(shù)的形式如下:

static void __exit cleanup_function(void) {   
 //釋放代碼  
}  
module_exit(cleanup_function); 

模塊卸載函數(shù)在模塊卸載時被調(diào)用,不返回任何值,必須以”module_exit(函數(shù)名)”的形式來指定
與__init一樣__exit也可以使對應(yīng)函數(shù)在運行完成后自動回收內(nèi)存。

一般來說,模塊卸載函數(shù)完成與模塊加載函數(shù)相反的功能:
如果模塊加載函數(shù)注冊了 XXX模塊,則模塊卸載函數(shù)應(yīng)注銷XXX。
若模塊加載函數(shù)動體申請了內(nèi)存,則模塊卸載函數(shù)應(yīng)釋放該內(nèi)存。
若模塊加載函數(shù)申請了硬件資源,則模塊卸載函數(shù)應(yīng)釋放這些硬件資源。
若模塊加載函數(shù)開啟了硬件,則模塊卸載函數(shù)應(yīng)關(guān)閉硬件。


內(nèi)核時間管理
(1)內(nèi)核中的時間概念
    時間管理在linux內(nèi)核中占有非常重要的作用。
    相對于事件驅(qū)動而言,內(nèi)核中有大量函數(shù)是基于時間驅(qū)動的。
    有些函數(shù)是周期執(zhí)行的,比如每10毫秒刷新一次屏幕;
    有些函數(shù)是推后一定時間執(zhí)行的,比如內(nèi)核在500毫秒后執(zhí)行某項任務(wù)。
    要區(qū)分:
    *絕對時間和相對時間
    *周期性產(chǎn)生的事件和推遲執(zhí)行的事件
    周期性事件是由系統(tǒng)系統(tǒng)定時器驅(qū)動的
 
(2)HZ值
    內(nèi)核必須在硬件定時器的幫助下才能計算和管理時間。
    定時器產(chǎn)生中斷的頻率稱為節(jié)拍率(tick rate)。
    在內(nèi)核中指定了一個變量HZ,內(nèi)核初始化的時候會根據(jù)這個值確定定時器的節(jié)拍率。
    HZ定義在<asm/param.h>,在i386平臺上,目前采用的HZ值是1000。
    也就是時鐘中斷每秒發(fā)生1000次,周期為1毫秒。即:
    #define HZ 1000
 
    注意!HZ不是個固定不變的值,它是可以更改的,可以在內(nèi)核源代碼配置的時候輸入。
    不同的體系結(jié)構(gòu)其HZ值是不一樣的,比如arm就采用100。
    如果在驅(qū)動中要使用系統(tǒng)的中斷頻率,直接使用HZ,而不要用100或1000
 
 
    a.理想的HZ值
        i386的HZ值一直采用100,直到2.5版后才改為1000。
        提高節(jié)拍率意味著時鐘中斷產(chǎn)生的更加頻繁,中斷處理程序也會更頻繁地執(zhí)行。
 
        帶來的好處有:
        *內(nèi)核定時器能夠以更高的頻率和更高的準(zhǔn)確度運行
        *依賴定時器執(zhí)行的系統(tǒng)調(diào)用,比如poll()和select(),運行的精度更高
        *提高進(jìn)程搶占的準(zhǔn)確度
        (縮短了調(diào)度延時,如果進(jìn)程還剩2ms時間片,在10ms的調(diào)度周期下,進(jìn)程會多運行8ms。
        由于耽誤了搶占,對于一些對時間要求嚴(yán)格的任務(wù)會產(chǎn)生影響)
 
        壞處有:
        *節(jié)拍率要高,系統(tǒng)負(fù)擔(dān)越重。
        中斷處理程序?qū)⒄加酶嗟奶幚砥鲿r間。
 
 (3)jiffies
    全局變量jiffies用于記錄系統(tǒng)啟動以來產(chǎn)生的節(jié)拍的總數(shù)。
    啟動時,jiffies初始化為0,此后每次時鐘中斷處理程序都會增加該變量的值。
    這樣,系統(tǒng)啟動后的運行時間就是jiffies/HZ秒
 
    jiffies定義于<linux/jiffies.h>中:
    extern unsigned long volatile jiffies;
 
    jiffies變量總是為unsigned long型。
    因此在32位體系結(jié)構(gòu)上是32位,而在64位體系上是64位。
    對于32位的jiffies,如果HZ為1000,49.7天后會溢出。
    雖然溢出的情況不常見,但程序在檢測超時時仍然可能因為回繞而導(dǎo)致錯誤。
    linux提供了4個宏來比較節(jié)拍計數(shù),它們能正確地處理節(jié)拍計數(shù)回繞。 
 
 

  #include <linux/jiffies.h> 
  #define time_after(unknown, known)    // unknow > known 
  #define time_before(unknown, known)   // unknow < known 
  #define time_after_eq(unknown, known)  // unknow >= known 
  #define time_before_eq(unknown, known)  // unknow <= known 
 

    unknown通常是指jiffies,known是需要對比的值(常常是一個jiffies加減后計算出的相對值)
 
    例: 

  unsigned long timeout = jiffies + HZ/2; /* 0.5秒后超時 */ 
  ... 
  if(time_before(jiffies, timeout)){ 
    /* 沒有超時,很好 */ 
  }else{ 
    /* 超時了,發(fā)生錯誤 */ 

     
    time_before可以理解為如果在超時(timeout)之前(before)完成
 
 
    *系統(tǒng)中還聲明了一個64位的值jiffies_64,在64位系統(tǒng)中jiffies_64和jiffies是一個值。
    可以通過get_jiffies_64()獲得這個值。
 
    *使用 

  u64 j2; 
    j2 = get_jiffies_64(); 

 
 (4)獲得當(dāng)前時間
    驅(qū)動程序中一般不需要知道墻鐘時間(也就是年月日的時間)。但驅(qū)動可能需要處理絕對時間。
    為此,內(nèi)核提供了兩個結(jié)構(gòu)體,都定義在<linux/time.h>: 

a.

  struct timeval { 
   time_t tv_sec; /* seconds */ 
   suseconds_t tv_usec; /* microseconds */ 
  }; 

    較老,但很流行。采用秒和毫秒值,保存了1970年1月1日0點以來的秒數(shù) 

b.

  struct timespec { 
   time_t tv_sec; /* seconds */ 
   long tv_nsec; /* nanoseconds */ 
  }; 

    較新,采用秒和納秒值保存時間。
 
    c.do_gettimeofday()
        該函數(shù)用通常的秒或微秒來填充一個指向struct timeval的指針變量,原型如下: 

    #include <linux/time.h> 
    void do_gettimeofday(struct timeval *tv); 
 

    d.current_kernel_time()
        該函數(shù)可用于獲得timespec 
       

#include <linux/time.h> 
    struct timespec current_kernel_time(void);


確定時間的延遲執(zhí)行 
    設(shè)備驅(qū)動程序經(jīng)常需要將某些特定代碼延遲一段時間后執(zhí)行,通常是為了讓硬件能完成某些任務(wù)。
    長于定時器周期(也稱為時鐘嘀嗒)的延遲可以通過使用系統(tǒng)時鐘完成,而非常短的延時則通過軟件循環(huán)的方式完成
     
 
(1)短延時
    對于那些最多幾十個毫秒的延遲,無法借助系統(tǒng)定時器。
    系統(tǒng)通過軟件循環(huán)提供了下面的延遲函數(shù): 

  #include <linux/delay.h> 
  /* 實際在<asm/delay.h> */ 
  void ndelay(unsigned long nsecs); /*延遲納秒 */ 
  void udelay(unsigned long usecs); /*延遲微秒 */ 
  void mdelay(unsigned long msecs); /*延遲毫秒 */ 

 
    這三個延遲函數(shù)均是忙等待函數(shù),在延遲過程中無法運行其他任務(wù)。
 
(2)長延時
    a.在延遲到期前讓出處理器 

    while(time_before(jiffies, j1)) 
      schedule(); 

        在等待期間可以讓出處理器,但系統(tǒng)無法進(jìn)入空閑模式(因為這個進(jìn)程始終在進(jìn)行調(diào)度),不利于省電。
 
    b.超時函數(shù) 

    #include <linux/sched.h> 
    signed long schedule_timeout(signed long timeout); 

 
    使用方式: 

  set_current_state(TASK_INTERRUPTIBLE); 
  schedule_timeout(2*HZ); /* 睡2秒 */ 

    進(jìn)程經(jīng)過2秒后會被喚醒。如果不希望被用戶空間打斷,可以將進(jìn)程狀態(tài)設(shè)置為TASK_UNINTERRUPTIBLE。

#include <linux/init.h> 
#include <linux/module.h> 
#include <linux/time.h> 
#include <linux/sched.h> 
#include <linux/delay.h> 
 
static int __init test_init(void) 
{ 
  set_current_state(TASK_INTERRUPTIBLE); 
  schedule_timeout(5 * HZ); 
  printk(KERN_INFO "Hello Micky\n"); 
  return 0; 
} 
 
static void __exit test_exit(void) 
{ 
} 
 
module_init(test_init); 
module_exit(test_exit); 
 
MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("Micky Liu"); 
MODULE_DESCRIPTION("Test for delay"); 


(3)等待隊列
    使用等待隊列也可以實現(xiàn)長延遲。
    在延遲期間,當(dāng)前進(jìn)程在等待隊列中睡眠。
    進(jìn)程在睡眠時,需要根據(jù)所等待的事件鏈接到某一個等待隊列。
 
    a.聲明等待隊列
        等待隊列實際上就是一個進(jìn)程鏈表,鏈表中包含了等待某個特定事件的所有進(jìn)程。 

    #include <linux/wait.h> 
    struct __wait_queue_head { 
      spinlock_t lock; 
      struct list_head task_list; 
    }; 
    typedef struct __wait_queue_head wait_queue_head_t; 

 
        要想把進(jìn)程加入等待隊列,驅(qū)動首先要在模塊中聲明一個等待隊列頭,并將它初始化。
 
        靜態(tài)初始化 
     

    DECLARE_WAIT_QUEUE_HEAD(name); 

 
        動態(tài)初始化 

      wait_queue_head_t my_queue; 
      init_waitqueue_head(&my_queue); 

 
    b.等待函數(shù)
        進(jìn)程通過調(diào)用下面函數(shù)可以在某個等待隊列中休眠固定的時間: 

    #include <linux/wait.h> 
    long wait_event_timeout(wait_queue_head_t q,condition, long timeout); 
    long wait_event_interruptible_timeout(wait_queue_head_t q, condition, long timeout);


        調(diào)用這兩個函數(shù)后,進(jìn)程會在給定的等待隊列q上休眠,但會在超時(timeout)到期時返回。
        如果超時到期,則返回0,如果進(jìn)程被其他事件喚醒,則返回剩余的時間數(shù)。
        如果沒有等待條件,則將condition設(shè)為0
 
        使用方式: 

    wait_queue_head_t wait; 
    init_waitqueue_head(&wait); 
    wait_event_interruptible_timeout(wait, 0, 2*HZ); 
    /*當(dāng)前進(jìn)程在等待隊列wait中睡2秒 */ 

 
 
 
(4)內(nèi)核定時器
    還有一種將任務(wù)延遲執(zhí)行的方法是采用內(nèi)核定時器。
    與前面幾種延遲方法不同,內(nèi)核定時器并不會阻塞當(dāng)前進(jìn)程,
    啟動一個內(nèi)核定時器只是聲明了要在未來的某個時刻執(zhí)行一項任務(wù),當(dāng)前進(jìn)程仍然繼續(xù)執(zhí)行。
    不要用定時器完成硬實時任務(wù)
 
    定時器由結(jié)構(gòu)timer_list表示,定義在<linux/timer.h> 

  struct timer_list{ 
    struct list_head entry; /* 定時器鏈表 */ 
    unsigned long expires; /* 以jiffies為單位的定時值 */ 
    spinlock_t lock; 
    void(*function)(unsigned long); /* 定時器處理函數(shù) */ 
    unsigned long data; /* 傳給定時器處理函數(shù)的參數(shù) */ 
  } 

 
    內(nèi)核在<linux/timer.h>中提供了一系列管理定時器的接口。
 
    a.創(chuàng)建定時器 

    struct timer_list my_timer; 

 
    b.初始化定時器 

    init_timer(&my_timer); 
    /* 填充數(shù)據(jù)結(jié)構(gòu) */ 
    my_timer.expires = jiffies + delay; 
    my_timer.data = 0; 
    my_timer.function = my_function; /*定時器到期時調(diào)用的函數(shù)*/ 

 
    c.定時器的執(zhí)行函數(shù)
        超時處理函數(shù)的原型如下: 

    void my_timer_function(unsigned long data); 

        可以利用data參數(shù)用一個處理函數(shù)處理多個定時器??梢詫ata設(shè)為0
 
    d.激活定時器 

    add_timer(&my_timer); 

        定時器一旦激活就開始運行。
 
    e.更改已激活的定時器的超時時間 

    mod_timer(&my_timer, jiffies+ney_delay); 

        可以用于那些已經(jīng)初始化但還沒激活的定時器,
        如果調(diào)用時定時器未被激活則返回0,否則返回1。
        一旦mod_timer返回,定時器將被激活。
 
    f.刪除定時器 

    del_timer(&my_timer); 

        被激活或未被激活的定時器都可以使用,如果調(diào)用時定時器未被激活則返回0,否則返回1。
        不需要為已經(jīng)超時的定時器調(diào)用,它們被自動刪除
 
    g.同步刪除 

  del_time_sync(&my_timer); 

    在smp系統(tǒng)中,確保返回時,所有的定時器處理函數(shù)都退出。不能在中斷上下文使用。 
   

#include <linux/init.h> 
#include <linux/module.h> 
#include <linux/time.h> 
#include <linux/sched.h> 
#include <linux/delay.h> 
#include <linux/timer.h> 
 
struct timer_list my_timer; 
 
static void timer_handler(unsigned long arg) 
{ 
  printk(KERN_INFO "%s %d Hello Micky! arg=%lu\n",__func__, __LINE__, arg ); 
} 
 
static int __init test_init(void) 
{ 
  init_timer(&my_timer); 
 
  my_timer.expires = jiffies + 5 * HZ; 
  my_timer.function = timer_handler; 
  my_timer.data = 10; 
  add_timer(&my_timer); 
 
  return 0; 
} 
 
static void __exit test_exit(void) 
{ 
  del_timer(&my_timer); 
} 
 
module_init(test_init); 
module_exit(test_exit); 
 
MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("Micky Liu"); 
MODULE_DESCRIPTION("Test for timer"); 

#include <linux/init.h> 
#include <linux/module.h> 
#include <linux/time.h> 
#include <linux/sched.h> 
#include <linux/delay.h> 
#include <linux/timer.h> 
 
struct timer_list my_timer; 
 
static void timer_handler(unsigned long arg) 
{ 
  printk(KERN_INFO "%s %d Hello Micky! arg=%lu\n",__func__, __LINE__, arg ); 
} 
 
static int __init test_init(void) 
{ 
  init_timer(&my_timer); 
 
  //my_timer.expires = jiffies + 5 * HZ; 
  my_timer.function = timer_handler; 
  my_timer.data = 10;  
  //add_timer(&my_timer); 
  mod_timer(&my_timer, jiffies + 5 * HZ); 
 
  return 0; 
} 
 
static void __exit test_exit(void) 
{ 
  del_timer(&my_timer); 
} 
 
module_init(test_init); 
module_exit(test_exit); 
 
MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("Micky Liu"); 
MODULE_DESCRIPTION("Test for timer"); 

 
不確定時間的延遲執(zhí)行
(1)什么是不確定時間的延遲
    前面介紹的是確定時間的延遲執(zhí)行,但在寫驅(qū)動的過程中經(jīng)常遇到這種情況:
    用戶空間程序調(diào)用read函數(shù)從設(shè)備讀數(shù)據(jù),但設(shè)備中當(dāng)前沒有產(chǎn)生數(shù)據(jù)。
    此時,驅(qū)動的read函數(shù)默認(rèn)的操作是進(jìn)入休眠,一直等待到設(shè)備中有了數(shù)據(jù)為止。
 
    這種等待就是不定時的延遲,通常采用休眠機(jī)制來實現(xiàn)。
 
 
(2)休眠
    休眠是基于等待隊列實現(xiàn)的,前面我們已經(jīng)介紹過wait_event系列函數(shù),
    但現(xiàn)在我們將不會有確定的休眠時間。
 
    當(dāng)進(jìn)程被置入休眠時,會被標(biāo)記為特殊狀態(tài)并從調(diào)度器的運行隊列中移走。
    直到某些事件發(fā)生后,如設(shè)備接收到數(shù)據(jù),則將進(jìn)程重新設(shè)為運行態(tài)并進(jìn)入運行隊列進(jìn)行調(diào)度。
    休眠函數(shù)的頭文件是<linux/wait.h>,具體的實現(xiàn)函數(shù)在kernel/wait.c中。
 
    a.休眠的規(guī)則
        *永遠(yuǎn)不要在原子上下文中休眠
        *當(dāng)被喚醒時,我們無法知道睡眠了多少時間,也不知道醒來后是否獲得了我們需要的資源
        *除非知道有其他進(jìn)程會在其他地方喚醒我們,否則進(jìn)程不能休眠
 
    b.等待隊列的初始化
        見前文
 
    c.休眠函數(shù)
        linux最簡單的睡眠方式為wait_event宏。該宏在實現(xiàn)休眠的同時,檢查進(jìn)程等待的條件。
 
        A. 

void wait_event( 
       wait_queue_head_t q, 
       int condition); 
 

        B. 

int wait_event_interruptible(wait_queue_head_t q, int condition); 

            q: 是等待隊列頭,注意是采用值傳遞。
            condition: 任意一個布爾表達(dá)式,在條件為真之前,進(jìn)程會保持休眠。
            注意!進(jìn)程需要通過喚醒函數(shù)才可能被喚醒,此時需要檢測條件。
            如果條件滿足,則被喚醒的進(jìn)程真正醒來;
            如果條件不滿足,則進(jìn)程繼續(xù)睡眠。
 
 
    d.喚醒函數(shù)
        當(dāng)我們的進(jìn)程睡眠后,需要由其他的某個執(zhí)行線程(可能是另一個進(jìn)程或中斷處理例程)喚醒。
        喚醒函數(shù):
            #include <linux/wait.h>
            1.

 void wake_up( 
        wait_queue_head_t *queue); 

 
            2. 

void wake_up_interruptible( 
        wait_queue_head_t *queue); 

 
        wake_up會喚醒等待在給定queue上的所有進(jìn)程。
        而wake_up_interruptible喚醒那些執(zhí)行可中斷休眠的進(jìn)程。
        實踐中,約定做法是在使用wait_event時使用wake_up,而使用wait_event_interruptible時使用wake_up_interruptible。

相關(guān)文章

  • C語言實現(xiàn)三子棋游戲的示例代碼

    C語言實現(xiàn)三子棋游戲的示例代碼

    今天我們將會用C語言實現(xiàn)三子棋。所謂三子棋,就是三行三列的棋盤,玩家可以和電腦下棋,率先連成三個的獲勝。話不多說,我們開始吧
    2022-10-10
  • C++輕量級界面開發(fā)框架ImGUI介紹小結(jié)

    C++輕量級界面開發(fā)框架ImGUI介紹小結(jié)

    如果從事過C++?Windows客戶端開發(fā),大家對MFC、Qt、DuiLib等各種DirectUI應(yīng)該有了解,本篇給大家介紹一個超級輕量級的C++開源跨平臺圖形界面框架ImGUI,感興趣的可以了解一下
    2021-11-11
  • c++中vector<int>和vector<int*>的用法及區(qū)別

    c++中vector<int>和vector<int*>的用法及區(qū)別

    這篇文章主要介紹了c++中vector<int>和vector<int*>的用法及區(qū)別,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2013-10-10
  • C++強(qiáng)制類型轉(zhuǎn)換的四種方式

    C++強(qiáng)制類型轉(zhuǎn)換的四種方式

    本文主要介紹了C++強(qiáng)制類型轉(zhuǎn)換的四種方式,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 基于VC中使用ForceInclude來強(qiáng)制包含stdafx.h的解決方法

    基于VC中使用ForceInclude來強(qiáng)制包含stdafx.h的解決方法

    本篇文章是對VC中使用ForceInclude來強(qiáng)制包含stdafx.h的解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • 基于QT5的文件讀取程序的實現(xiàn)

    基于QT5的文件讀取程序的實現(xiàn)

    本文主要介紹了基于QT5的文件讀取程序的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • C++之如何設(shè)置字體顏色

    C++之如何設(shè)置字體顏色

    很多C++的初學(xué)者發(fā)現(xiàn),控制臺的顏色永遠(yuǎn)是黑白的,這未免太單調(diào)了,怎么才能使字體像那些軟件一樣呈彩色呢?現(xiàn)在,我們就將學(xué)習(xí)C++ 設(shè)置字體顏色的方法
    2023-08-08
  • C 語言中實現(xiàn)環(huán)形緩沖區(qū)

    C 語言中實現(xiàn)環(huán)形緩沖區(qū)

    本文主要是介紹 C語言實現(xiàn)環(huán)形緩沖區(qū),并附有詳細(xì)實現(xiàn)代碼,具有一定的參考價值,希望能幫助有需要的小伙伴
    2016-07-07
  • C++實現(xiàn)職工信息管理系統(tǒng)

    C++實現(xiàn)職工信息管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了c++實現(xiàn)職工信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C++獲取字符串長度的幾個函數(shù)方式

    C++獲取字符串長度的幾個函數(shù)方式

    這篇文章主要介紹了C++獲取字符串長度的幾個函數(shù)方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12

最新評論

广德县| 丰都县| 临邑县| 丰宁| 天水市| 新蔡县| 高碑店市| 礼泉县| 香格里拉县| 芜湖县| 远安县| 永仁县| 扬州市| 凉城县| 武胜县| 库伦旗| 南澳县| 正安县| 托里县| 普陀区| 林口县| 巴楚县| 涡阳县| 鲜城| 景谷| 邮箱| 怀来县| 嘉荫县| 邓州市| 徐州市| 长宁县| 阿尔山市| 赣榆县| 永安市| 兰西县| 平度市| 资讯 | 贵州省| 镇赉县| 大足县| 逊克县|