小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

阻塞與非阻塞I/O

 昵稱7823907 2011-09-30


阻塞操作是指在執(zhí)行設(shè)備操作時(shí)若不能獲得資源,則掛起進(jìn)程,直到滿足可操作的條件后再進(jìn)行操作。被掛起的進(jìn)程進(jìn)入休眠狀態(tài),被從調(diào)度器的運(yùn)行隊(duì)列移走,直到等待條件被滿足。而非阻塞操作的進(jìn)程不能進(jìn)行設(shè)備時(shí)并不掛起,它或者放棄,或者不停地查詢,直到可以進(jìn)行操作為止。

阻塞的進(jìn)程會(huì)進(jìn)入睡眠狀態(tài),必須有一個(gè)地方能夠喚醒休眠的進(jìn)程。喚醒進(jìn)程的地方最大可能發(fā)生在中斷里面,因?yàn)橛布Y源獲得的同時(shí)往往伴隨一個(gè)中斷。

 

等待隊(duì)列

可以使用等待隊(duì)列(wait queue)來喚醒阻塞進(jìn)程。wait queue很早就作為一個(gè)基本的功能單位出現(xiàn)在linux內(nèi)核里了,它以隊(duì)列為基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),與進(jìn)程調(diào)度機(jī)制緊密結(jié)合,能夠用于實(shí)現(xiàn)內(nèi)核中的異步通知機(jī)制。等待隊(duì)列可以用來同步對(duì)系統(tǒng)資源的訪問,信號(hào)量在內(nèi)核中也依賴等待隊(duì)列來實(shí)現(xiàn)。

1.定義等待隊(duì)列頭

 wait_queue_head my_queue;

2. 初始化等待隊(duì)列頭

init_waitqueue_head(&my_queue);

   DELCARE_WAIT_QUEUE_HEAD(name)/定義并初始化

3. 定義等待隊(duì)列

DECLARE_WAITQUEUE(name,tsk)

4. 添加/移除等待隊(duì)列

void fastcall add_wait_queue(wait_queue_head_t *q,wait_queue_t *wait);

void fastcall remove_wait_queue(wait_queue_head_t *q,wait_queue_t *wait);

5. 等待事件

wait_event(queue,condition);

wait_event_interruptible(queue,condition);

wait_event_timeout(queue,timeout);

wait_event_interruptible_timeout(queue,condition,timeout);

 

wait_event()代碼:

  #define wait_event(wq,condition)

do {

          if (condition)

                  break;

          __wait_event(wq,condition);//添加到等待隊(duì)列

} while (0)

 

#define __wait_event(wq,condition)

do {

          DEFINE_WAIT(__wait);

         

          for (;;) {

                  prepare_to_wait(&wq,&__wait,TASK_UNINTERRUPTIBLE);

                  if (condition)

                          break;

                  schedule();//放棄cpu

          }

          finsh_wait(&wq,&__wait);

} while(0)

 

void fastcall prepare_to_wait(wait_queue_head_t *q,wait_queue_t *wait,int state)

{

          unsigned long flags;

 

          wait->flags &= ~WQ_FLAG_EXCLUSIVE;

          sping_lock_irqsave(&q->lock,flags);

          if (list_empty(&wait->task_list))

                  __add_wait_queue(q,wait);//添加等待隊(duì)列

          if (is_sync_wait(wait))

                        set_current_state(state);//改變當(dāng)前進(jìn)程的狀態(tài)為休眠

                spin_unlock_irqrestore(&q->lock,flags);

}

 

void fastcall finsh_wait(wait_queue_head_t *q,wait_queue_t *wait)

{

        unsigned long flags;

 

        __set_current_state(TASK_RUNNING);//恢復(fù)當(dāng)前進(jìn)程的狀態(tài)為TASK_RUNING

        if (!list_empty_careful(&wait->task_list)) {

                spin_lock_irqsave(&q->lock,flags);

                list_del_init(&wait->task_list);

                spin_unlock_irqrestore(&q->lock,flags);

}

 

6. 喚醒隊(duì)列

void wake_up(wait_queue_head_t *queue);

void wake_up_interruptible(wait_queue_head_t  *queue);

wake_up()喚醒wait_event()或wait_event_timeout(),wake_up_interruptible()或wake_up_interruptible_timeout().wake_up()可喚醒處于TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE的進(jìn)程,而wake_up_interruptibel()只能喚醒處于TASK_INTERRUPTIBLE的進(jìn)程。

7.在等待隊(duì)列上睡眠

sleep_on(wait_queue_head_t *q);

interruptible_sleep_on(wait_queue_head_t *q);

sleep_on()將目前進(jìn)程的狀態(tài)置成TASK_UNINTERRUPTIBLE,并定義一個(gè)等待隊(duì)列,之后把它附屬到等待隊(duì)列頭q,直到資源可獲得,q引導(dǎo)的等待隊(duì)列被喚醒。

interruptible_sleep_on()與sleep()類似,其作用是將目前進(jìn)程的狀態(tài)置成TASK_INTERRUPTIBLE,并定義一個(gè)等待隊(duì)列,之后把它附屬到等待隊(duì)列頭q,直到資源可獲得的,q引導(dǎo)的等待隊(duì)列被喚醒或者收到信號(hào)。

sleep_on()與wake_up()成對(duì)使用,interruptible_sleep_on()與wake_up_interruptible()成對(duì)使用。

sleep_on():

void fastcall __sched sleep_on(wait_queue_head_t *q)

{

          SLEEP_ON_VAR

          /*

          #define SLEEP_ONVAR

          unsigned long flags;

          wait_queue_t wait;

          init_waitqueue_entry(&wait,current);*/

          current->state = TASK_UNINTERRUPTIBLE

 

SLEEP_ON_HEAD

/*

#define SLEEP_ONHEAD

spin_lock_irqsave(&q->lock,flags);

__add_wait_queue(q,&wait);

sping_unlock(&q->lock,flags);*/

 

schedule();

SLEEP_ON_TALL

/*

#define SLEEP_ON_TALL

spin_lock_irq(&q->lock);

__remove_wait_queue(q,&wait);*/

spin_unlock_irqrestore(&q->lock,flags);*/

}

 

interruptible_sleep_on():

void fastcall __sched interruptible_sleep_on(wait_queue_head_t *q)

{

          SLEEP_ON_VAR

 

          current->state = TASK_INTERRUPTIBLE;

 

          SLEEP_ON_HEAD

          schedule();

          SLEEP_ON_TALL

}

 

note:在內(nèi)核中使用set_current_state()或__add_current_queue()函數(shù)來實(shí)現(xiàn)目前進(jìn)程狀態(tài)的改變,直接采用current->state = TASK_INTERRUPTIBLE類似的賦值語句也是可行。通常而言,set_current_state()在任何環(huán)境下都可以使用,不會(huì)存在并發(fā)問題,但是效率要低于__add_current_queue().因此,許多設(shè)備驅(qū)動(dòng)并不調(diào)用sleep_on()或interruptible_sleep_on(),而是直接進(jìn)程狀態(tài)改變和切換。

 

輪詢操作

輪詢

使用非阻塞I/O的應(yīng)用程序通常會(huì)使用select()和poll()系統(tǒng)調(diào)用查詢?cè)O(shè)備是否可對(duì)設(shè)備進(jìn)行無阻塞的訪問。selecct()和poll()系統(tǒng)調(diào)用最終會(huì)引發(fā)設(shè)備驅(qū)動(dòng)中的poll()函數(shù)被執(zhí)行。

應(yīng)用程序中的輪詢編程

應(yīng)用程序最廣泛用到select()系統(tǒng)調(diào)用。

int select(int numfds,fd_set *reafds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

struct timeval

{

          int tv_sec;//second

          int tv_usec;//1/1000 second

}

 

FD_ZERO(fd_set *set);//清零set

FD_SET(int fd, fd_set *set);//加fd到set

FD_CLR(int fd, fd_set *set);//清除fd從set

FD_ISSET(int fd, fd_set *set);//判斷fd是否被置位

 

設(shè)備驅(qū)動(dòng)中的輪詢編程

設(shè)備驅(qū)動(dòng)中poll()函數(shù):

unsigned int (*poll)(struct file *filp, struct poll_table *watit);

struct poll_table 輪詢表。

此函數(shù),對(duì)可能引起設(shè)備文件狀態(tài)變化的等待隊(duì)列調(diào)用poo_wait()函數(shù),將對(duì)應(yīng)的等待隊(duì)列頭添加到poll_table; 返回表示是是否能對(duì)設(shè)備進(jìn)行無阻塞讀寫訪問的掩碼。

poll_wait()注冊(cè)等待隊(duì)列:

void poll_wait(struct file *filp, wait_queue_head_t *queue, poll_table *wait);

只是把當(dāng)前進(jìn)程加入到wait等待隊(duì)列表中。

驅(qū)動(dòng)程序poll()返回設(shè)備資源可獲取狀態(tài),即POLLIN,POLLOUT,POLLPRI,POLLERR,POLLNVAL等宏位“或”的結(jié)果。

 

阻塞與非阻塞訪問是IO訪問的兩種I/O操作暫時(shí)不可進(jìn)行時(shí)會(huì)讓進(jìn)程睡眠。

在設(shè)備驅(qū)動(dòng)中阻塞IO一般基于等待隊(duì)列,等待隊(duì)列可用于同步驅(qū)動(dòng)中事件發(fā)生的先后順序。使用非阻塞IO的應(yīng)用程序也可借助輪詢函數(shù)來查詢?cè)O(shè)備是否能立即被訪問,用戶空間調(diào)用select()和poll()接口,設(shè)備驅(qū)動(dòng)提供poll()函數(shù),設(shè)備驅(qū)動(dòng)的poll()本身不會(huì)阻塞,但是poll()和select系統(tǒng)調(diào)用則會(huì)阻塞地等待文件描述集合中的至少一個(gè)可訪問或超時(shí)。

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多