成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

阻塞和非阻塞的實現

存儲 存儲軟件
我們可能都已經聽過阻塞非阻塞的概念,本文以tcp中的connect系統調用為例子(基于1.12.13內核,新版的原理類似,但是過程就很復雜了,有時間再分析),分析阻塞和非阻塞是什么并且看他是如何實現的。話不多說,直接開始。

[[403799]]

本文轉載自微信公眾號「編程雜技」,作者theanarkh。轉載本文請聯系編程雜技公眾號。

我們可能都已經聽過阻塞非阻塞的概念,本文以tcp中的connect系統調用為例子(基于1.12.13內核,新版的原理類似,但是過程就很復雜了,有時間再分析),分析阻塞和非阻塞是什么并且看他是如何實現的。話不多說,直接開始。

  1. static int inet_connect(struct socket *sock, struct sockaddr * uaddr, 
  2.       int addr_len, int flags) 
  3.   struct sock *sk=(struct sock *)sock->data; 
  4.   // 調用底層的連接函數,發一個syn包 
  5.   err = sk->prot->connect(sk, (struct sockaddr_in *)uaddr, addr_len); 
  6.   if (err < 0)  
  7.     return(err); 
  8.  
  9.   // 還沒建立連接成功并且是非阻塞的方式,直接返回 
  10.   if (sk->state != TCP_ESTABLISHED &&(flags & O_NONBLOCK))  
  11.       return(-EINPROGRESS); 
  12.   // 早期通過關中斷防止競態情況 
  13.   cli();  
  14.   // 連接建立中,阻塞當前進程 
  15.   while(sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)  
  16.   { 
  17.     // 阻塞進程 
  18.     interruptible_sleep_on(sk->sleep); 
  19.     // 連接失敗 
  20.     if(sk->err && sk->protocol == IPPROTO_TCP) 
  21.     { 
  22.       sti(); 
  23.       sock->state = SS_UNCONNECTED; 
  24.       err = -sk->err; 
  25.       sk->err=0; 
  26.       return err; /* set by tcp_err() */ 
  27.     } 
  28.   } 
  29.   sti(); 
  30.   // 連接建立 
  31.   sock->state = SS_CONNECTED; 
  32.   // 返回成功 
  33.   return(0); 

我們看到connect函數首先會調用tcp層的函數發送一個sync包,然后根據socket的屬性(阻塞非阻塞,可以通過setsocketopt設置)做下一步處理,如果是非阻塞,那么就比較簡單,直接返回給應用層。這也是非阻塞+事件驅動架構中的做法。因為這種架構下通常是單進程的,要避免阻塞進程,那么返回后什么時候才能知道連接成功呢?這就是epoll提供的機制,當連接成功后,tcp層會通知epoll,epoll就會通知應用層。下面我們繼續分析阻塞的過程,interruptible_sleep_on(sk->sleep)。我們看到socket中有一個sleep字段,該字段用于管理隊列。我們看看interruptible_sleep_on

  1. void interruptible_sleep_on(struct wait_queue **p) 
  2.   __sleep_on(p,TASK_INTERRUPTIBLE); 
  3.  
  4. static inline void __sleep_on(struct wait_queue **p, int state) 
  5.   unsigned long flags; 
  6.   struct wait_queue wait = { currentNULL }; 
  7.   current->state = state; 
  8.   add_wait_queue(p, &wait); 
  9.   save_flags(flags); 
  10.   sti(); 
  11.   schedule(); 
  12.   remove_wait_queue(p, &wait); 
  13.   restore_flags(flags); 

這里我們只關注兩個地方add_wait_queue和schedule。add_wait_queue就是把一個節點插入隊列。我們看看wait_queue的定義。

  1. struct wait_queue { 
  2.     struct task_struct * task; 
  3.     struct wait_queue * next
  4. }; 

所以add_wait_queue執行完之后架構如下。

接著調用schedule調度其他進程執行,我們發現這時候當前進程的狀態是TASK_INTERRUPTIBLE,所以是不會被調度執行的。這就是進程阻塞的原理,主要是兩個過程

1 加入等待隊列

2 讓出CPU,調度其他進程執行。

我們這個進程什么時候被喚醒呢?我們從收到sync的回包開始分析。具體邏輯在tcp_rcv中。

  1. if(sk->state==TCP_SYN_SENT) 
  2.     { 
  3.       /* Crossed SYN or previous junk segment */ 
  4.       // 發送了syn包,收到ack包說明可能是建立連接的ack包 
  5.       if(th->ack) 
  6.      { 
  7.         // 發送第三次握手的ack包,進入連接建立狀態 
  8.         tcp_send_ack(sk->sent_seq,sk->acked_seq,sk,th,sk->daddr); 
  9.         tcp_set_state(sk, TCP_ESTABLISHED); 
  10.         // 喚醒阻塞在connect函數的進程 
  11.         if(!sk->dead) 
  12.         { 
  13.           // 喚醒進程 
  14.           sk->state_change(sk); 
  15.           // 給進程發送SIGIO信號 
  16.           sock_wake_async(sk->socket, 0); 
  17.         } 
  18.       } 
  19.     } 

我們看到收到ack后,tcp層調用state_change回調,state_change的值是def_callback1。

  1. static void def_callback1(struct sock *sk) 
  2.   if(!sk->dead) 
  3.     wake_up_interruptible(sk->sleep); 

我們看到這里會調用wake_up_interruptible喚醒進程。我們看看實現。

  1. void wake_up_interruptible(struct wait_queue **q) 
  2.   struct wait_queue *tmp; 
  3.   struct task_struct * p; 
  4.  
  5.   if (!q || !(tmp = *q)) 
  6.     return
  7.   do { 
  8.     if ((p = tmp->task) != NULL) { 
  9.       if (p->state == TASK_INTERRUPTIBLE) { 
  10.         p->state = TASK_RUNNING; 
  11.         if (p->counter > current->counter + 3) 
  12.           need_resched = 1; 
  13.       } 
  14.     } 
  15.     tmp = tmp->next
  16.   } while (tmp != *q); 

 

我們看到wake_up_interruptible會喚醒所有進程,這就是導致景群效應的地方,新版內核已經處理了相關問題。另外我們看到,這里這是修改進程為可執行狀態,但是不會立刻調度,要等下一次進程調度的時候才發生進程調度。以上就是進程阻塞和非阻塞的原理。

 

責任編輯:武曉燕 來源: 編程雜技
相關推薦

2012-10-10 10:00:27

同步異步開發Java

2022-06-22 08:16:29

異步非阻塞框架

2015-07-03 10:12:04

編程同步非阻塞

2019-07-23 11:01:57

Python同步異步

2017-03-01 16:40:12

Linux驅動技術設備阻塞

2012-02-22 21:15:41

unixIO阻塞

2025-02-17 13:23:34

Python同步阻塞MySQL

2023-03-15 08:39:07

遠程服務調用

2018-03-28 08:52:53

阻塞非阻塞I

2023-07-31 08:55:01

Java NIO非阻塞阻塞

2023-12-13 09:45:49

模型程序

2024-11-26 10:37:19

2023-12-06 07:28:47

阻塞IO異步IO

2024-09-23 17:15:28

Python并發并行

2013-08-09 09:27:31

2021-02-27 16:08:17

Java異步非阻塞

2011-12-07 17:17:02

JavaNIO

2018-01-11 08:24:45

服務器模型詳解

2021-02-04 10:50:11

網絡安全非阻塞模Winsock編程

2011-12-08 10:12:34

JavaNIO
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 99精品欧美一区二区蜜桃免费 | 国产高潮好爽受不了了夜色 | 久久99精品国产99久久6男男 | 欧美精品久久久 | 亚洲精品久久久一区二区三区 | 国产资源在线视频 | 久久精品国产99国产精品 | 毛片国产| 亚洲精品一区二区三区中文字幕 | www国产成人免费观看视频 | 亚洲成人一区二区 | 国产欧美精品区一区二区三区 | 国产精品性做久久久久久 | 国产一区 | 综合二区 | 国产一区二区视频在线 | 99热热| 日韩毛片在线视频 | 欧美在线一二三 | 欧美专区在线 | 亚洲精品一区二区三区蜜桃久 | 毛片久久久 | 久久精品视频一区二区 | 99精品在线观看 | 中文字幕在线免费观看 | 国产精品精品视频一区二区三区 | 精品国产乱码久久久久久图片 | 亚洲精品视频一区 | 日日操视频 | 在线伊人| 色婷婷综合久久久中字幕精品久久 | 久久久久久国产 | 日日摸日日碰夜夜爽亚洲精品蜜乳 | 欧美激情五月 | 久久最新| 99精品免费久久久久久日本 | 精区3d动漫一品二品精区 | 日韩综合一区 | 国产成人精品一区二区三区四区 | 91精品国产综合久久精品图片 | 免费观看色 |