Selector.wakeup实现注记

    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 -f -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调用了EPollArrayWrapper的interrupt方法:

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充分利用对了解这些细节很有帮助。
  文章转自庄周梦蝶  ,原文发布时间 2010-10-22

时间: 2024-08-07 00:59:30

Selector.wakeup实现注记的相关文章

envi ann evf-envi中如何把线性矢量文件转换为ann格式的注记

问题描述 envi中如何把线性矢量文件转换为ann格式的注记 envi中如何把线性矢量文件转换为ann格式的注记?急求谢谢,希望能给我解答下

《算法导论(原书第3版)》一本章注记

本章注记 关于算法的一般主题存在许多优秀的教科书,包括由以下作者编写的那些:Aho.Hopcroft和Ullman[5,6],Baase和Van Gelder[28],Brassard和Bratley[54],Dasgupta.Papadimitriou和Vazirani[82],Goodrich和Tamassia[148],Hofri[175],Horowitz.Sahni和Rajasekaran[181],Johnsonbaugh和Schaefer[193],Kingston[205],Kl

注记层配置参数的读取问题

问题描述 在ArcMap中把点.线.面图层的Label转换成注记层,在mxd中只保留这些注记层.我有几个问题请问各位大神指教:1.我怎么判断某个注记图层是从点层转换来的还是从线层.面层转换来的?2.对于由点层label转换来的注记层,从ArcMap中我可以看到旋转类型和旋转字段的设置,但在AO中我怎么才能读到这些设置呢?(本人菜鸟一个,恳请各位大神明示) 解决方案 解决方案二:参考:解决方案三:不错啊不错啊不错啊不错啊不错啊

Arcgis创建文本注记

问题描述 请教各位大神,有谁了解ArcGIS,在读取点图层,线图层的都正常的情况下,如何去读取或者创建文本图层呢,比如下图注记和基本农田注记,是如何实现的呢??

WebGIS中自定义互联网地图局部注记的一种方案

文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.    前言 实际项目中我们经常会遇到这样一种场景:地图底图可能是互联网地图(百度.高德.天地图)等等,同时我们自己又有某个区域单独的一套POI数据,我们需要将互联网地图中这个区域的原有POI数据进行遮罩然后只显示我们自己的POI数据. 针对这样的需求,我们首先想到的是能否我们只使用不包含注记的底图瓦片,然后再叠加上我们的POI数据.事实上,实际需求中还需要考虑一点

一道面试题注记

[java] public static int[] findTopNValues(int[] anyOldOrderValues, int n) { Arrays.sort(anyOldOrderValues); int[] result = new int[n]; System.arraycopy(anyOldOrderValues, anyOldOrderValues.length - n, result, 0, n); return result; } [/java] Arrays.so

注记修改高程-请问谁有根据旁边文字修改高程值

问题描述 请问谁有根据旁边文字修改高程值 请问怎么搞,有文字,但不成编组,也没有值.一按cass匹配反而成0了. 解决方案 根据旁边文字修改,看下文档能不能做到

java的nio之:java的nio系列教程之selector

一:Java NIO的selector的概述===>Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件.这样,一个单独的线程可以管理多个channel,从而管理多个网络连接. 二:Java NIO的为什么要使用selector===>仅用单个线程来处理多个Channels的好处是,只需要更少的线程来处理通道.事实上,可以只用一个线程处理所有的通道.对于操作系统来说,线程之间上下文切换的开销很大,而且每个线程都要占用系统的一些

Java NIO Selector

Java Nio  1 Java NIO Tutorial 2 Java NIO Overview 3 Java NIO Channel 4 Java NIO Buffer 5 Java NIO Scatter / Gather 6 Java NIO Channel to Channel Transfers 7 Java NIO Selector 8 Java NIO FileChannel 9 Java NIO SocketChannel 10 Java NIO ServerSocketCha