<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

    Selector.wakeup實現注記

    Posted on 2010-10-22 10:35 dennis 閱讀(6241) 評論(3)  編輯  收藏 所屬分類: java 、源碼解讀

        NIO中的Selector封裝了底層的系統調用,其中wakeup用于喚醒阻塞在select方法上的線程,它的實現很簡單,在linux上就是創建一個管道并加入poll的fd集合,wakeup就是往管道里寫一個字節,那么阻塞的poll方法有數據可讀就立即返回。證明這一點很簡單,strace即可知道:
    public class SelectorTest {
        
    public static void main(String[] args) throws Exception {
            Selector selector 
    = Selector.open();
            selector.wakeup();
        }
    }

         使用strace調用,只關心write的系統調用
    sudo strace --e write java SelectorTest

         輸出:
    Process 29181 attached
    Process 
    29182 attached
    Process 
    29183 attached
    Process 
    29184 attached
    Process 
    29185 attached
    Process 
    29186 attached
    Process 
    29187 attached
    Process 
    29188 attached
    Process 
    29189 attached
    Process 
    29190 attached
    Process 
    29191 attached
    [pid 
    29181] write(36"\1"1)          = 1
    Process 
    29191 detached
    Process 
    29184 detached
    Process 
    29181 detached

        有的同學說了,怎么證明這個write是wakeup方法調用的,而不是其他方法呢,這個很好證明,我們多調用幾次:
    public class SelectorTest {
        
    public static void main(String[] args) throws Exception {
            Selector selector 
    = Selector.open();
            selector.wakeup();
            selector.selectNow();
            selector.wakeup();
            selector.selectNow();
            selector.wakeup();
        }
    }

        修改程序調用三次wakeup,心細的朋友肯定注意到我們還調用了兩次selectNow,這是因為在兩次成功的select方法之間調用wakeup多次都只算做一次,為了顯示3次write,這里就每次調用前select一下將前一次寫入的字節讀到,同樣執行上面的strace調用,輸出:

    Process 29303 attached
    Process 
    29304 attached
    Process 
    29305 attached
    Process 
    29306 attached
    Process 
    29307 attached
    Process 
    29308 attached
    Process 
    29309 attached
    Process 
    29310 attached
    Process 
    29311 attached
    Process 
    29312 attached
    Process 
    29313 attached
    [pid 
    29303] write(36"\1"1)          = 1
    [pid 
    29303] write(36"\1"1)          = 1
    [pid 
    29303] write(36"\1"1)          = 1
    Process 
    29313 detached
    Process 
    29309 detached
    Process 
    29306 detached
    Process 
    29303 detached

         果然是3次write的系統調用,都是寫入一個字節,如果我們去掉selectNow,那么三次wakeup還是等于一次:
    public class SelectorTest {
        
    public static void main(String[] args) throws Exception {
            Selector selector 
    = Selector.open();
            selector.wakeup();
            selector.wakeup();
            selector.wakeup();
        }
    }
     
       輸出:
    Process 29331 attached
    Process 
    29332 attached
    Process 
    29333 attached
    Process 
    29334 attached
    Process 
    29335 attached
    Process 
    29336 attached
    Process 
    29337 attached
    Process 
    29338 attached
    Process 
    29339 attached
    Process 
    29340 attached
    Process 
    29341 attached
    [pid 
    29331] write(36"\1"1)          = 1
    Process 
    29341 detached
    Process 
    29337 detached
    Process 
    29334 detached
    Process 
    29331 detached

          wakeup方法的API說明沒有欺騙我們。wakeup方法的API還告訴我們,如果當前Selector沒有阻塞在select方法上,那么本次wakeup調用會在下一次select阻塞的時候生效,這個道理很簡單,wakeup方法寫入一個字節,下次poll等待的時候立即發現可讀并返回,因此不會阻塞。

         具體到源碼級別,在linux平臺上的wakeup方法其實調用了pipe創建了管道,wakeup調用了EPollArrayWrapperinterrupt方法:
    public  void interrupt() 

    {
            interrupt(outgoingInterruptFD);
    }

        實際調用的是interrupt(fd)的native方法,查看EPollArrayWrapper.c可見清晰的write系統調用:

    JNIEXPORT 
    void JNICALL
    Java_sun_nio_ch_EPollArrayWrapper_interrupt(JNIEnv 
    *env, jobject this, jint fd)
    {
        
    int fakebuf[1];
        fakebuf[
    0= 1;
        
    if (write(fd, fakebuf, 1< 0) {
            JNU_ThrowIOExceptionWithLastError(env,
    "write to interrupt fd failed");
        }
    }
        寫入一個字節的fakebuf。有朋友問起這個問題,寫個注記在此。strace充分利用對了解這些細節很有幫助。
     


    評論

    # re: Selector.wakeup實現注記  回復  更多評論   

    2010-10-22 11:01 by BucketLI
    好像在網絡IO中很有用的一個命令,記下了。
    然后能否多分享一些其他有用的網絡命令?

    # re: Selector.wakeup實現注記  回復  更多評論   

    2010-10-22 22:19 by 上情下愛
    不錯,謝謝~
    欣賞博主的鉆研和分享精神

    # re: Selector.wakeup實現注記  回復  更多評論   

    2011-05-09 21:56 by niumd
    讀了mina、netty的源碼,但是在閱讀您的文章后受益匪淺,覺得自己理解還不夠深入,希望那個樓主在多處精彩文章;謝謝分享。
    主站蜘蛛池模板: 亚洲一区二区三区影院 | 亚洲精品在线不卡| 久久久久久国产精品免费免费| 亚洲精品无码日韩国产不卡av| 一区国严二区亚洲三区| 全免费a级毛片免费看| 亚洲日本va一区二区三区| 色噜噜亚洲精品中文字幕| 福利免费观看午夜体检区| 国产成人无码精品久久久久免费| 亚洲黄色网址在线观看| 免费一级毛片在线观看| 久久精品无码专区免费东京热| 亚洲另类无码一区二区三区| 国产偷国产偷亚洲清高动态图 | 亚洲中文字幕无码av永久| 久久国产成人亚洲精品影院| 国产成人精品免费视频大| 男女啪啪免费体验区| 亚洲免费中文字幕| 国产成人精品久久亚洲| 成年在线网站免费观看无广告| 中文字幕av无码不卡免费| 亚洲av成人一区二区三区观看在线 | 久久久久国产成人精品亚洲午夜 | 成年性生交大片免费看| 中国极品美軳免费观看| 亚洲熟妇AV日韩熟妇在线| 亚洲av激情无码专区在线播放| 女人被弄到高潮的免费视频| 免费一级毛片在线播放视频| 校园亚洲春色另类小说合集| 亚洲视频在线观看免费视频| 国产国拍亚洲精品福利 | 国产免费牲交视频免费播放| 亚洲熟女www一区二区三区| 日韩亚洲AV无码一区二区不卡| 亚洲欧洲久久av| 日韩免费三级电影| 欧美最猛性xxxxx免费| 无码国产精品一区二区免费模式 |