zoukankan      html  css  js  c++  java
  • linux进程 阻塞和非阻塞操作

    在我们看全功能的 read 和 write 方法的实现之前, 我们触及的最后一点是决定何时使 进程睡眠. 有时实现正确的 unix 语义要求一个操作不阻塞, 即便它不能完全地进行下去.

    有时还有调用进程通知你他不想阻塞, 不管它的 I/O 是否继续. 明确的非阻塞 I/O 由 filp->f_flags 中的 O_NONBLOCK 标志来指示. 这个标志定义于 <linux/fcntl.h>, 被

    <linux/fs.h>自动包含. 这个标志得名自"打开-非阻塞", 因为它可在打开时指定(并且起

    初只能在那里指定). 如果你浏览源码, 你会发现一些对一个 O_NDELAY 标志的引用; 这 是一个替代 O_NONBLOCK 的名子, 为兼容 System V 代码而被接受的. 这个标志缺省地被 清除, 因为一个等待数据的进程的正常行为仅仅是睡眠. 在一个阻塞操作的情况下, 这是 缺省地, 下列的行为应当实现来符合标准语法:

    • · 如果一个进程调用 read 但是没有数据可用(尚未), 这个进程必须阻塞. 这个进程 在有数据达到时被立刻唤醒, 并且那个数据被返回给调用者, 即便小于在给方法的 count 参数中请求的数量.
    • · 如果一个进程调用 write 并且在缓冲中没有空间, 这个进程必须阻塞, 并且它必 须在一个与用作 read 的不同的等待队列中. 当一些数据被写入硬件设备, 并且在

    输出缓冲中的空间变空闲, 这个进程被唤醒并且写调用成功, 尽管数据可能只被部 分写入如果在缓冲只没有空间给被请求的 count 字节.

    这 2 句都假定有输入和输出缓冲; 实际上, 几乎每个设备驱动都有. 要求有输入缓冲是 为了避免丢失到达的数据, 当无人在读时. 相反, 数据在写时不能丢失, 因为如果系统调

    用不能接收数据字节, 它们保留在用户空间缓冲. 即便如此, 输出缓冲几乎一直有用, 对 于从硬件挤出更多的性能.

    在驱动中实现输出缓冲所获得的性能来自减少了上下文切换和用户级/内核级切换的次数. 没有一个输出缓冲(假定一个慢速设备), 每次系统调用接收这样一个或几个字符, 并且当 一个进程在 write 中睡眠, 另一个进程运行(那是一次上下文切换). 当第一个进程被唤 醒, 它恢复(另一次上下文切换), 写返回(内核/用户转换), 并且这个进程重新发出系统 调用来写入更多的数据(用户/内核转换); 这个调用阻塞并且循环继续. 增加一个输出缓 冲可允许驱动在每个写调用中接收大的数据块, 性能上有相应的提高. 如果这个缓冲足够 大, 写调用在第一次尝试就成功 -- 被缓冲的数据之后将被推到设备 -- 不必控制需要返 回用户空间来第二次或者第三次写调用. 选择一个合适的值给输出缓冲显然是设备特定的.

    我们不使用一个输入缓冲在 scull 中, 因为数据当发出 read 时已经可用. 类似的, 不用 输出缓冲, 因为数据被简单地拷贝到和设备关联的内存区. 本质上, 这个设备是一个缓冲, 因此额外缓冲的实现可能是多余的. 我们将在第 10 章见到缓冲的使用.

    如果指定 O_NONBLOCK, read 和 write 的行为是不同的. 在这个情况下, 这个调用简单 地返回 -EAGAIN(("try it agin")如果一个进程当没有数据可用时调用 read , 或者如果 当缓冲中没有空间时它调用 write .

    如你可能期望的, 非阻塞操作立刻返回, 允许这个应用程序轮询数据. 应用程序当使用 stdio 函数处理非阻塞文件中, 必须小心, 因为它们容易搞错一个的非阻塞返回为 EOF. 它们始终必须检查 errno.

    自然地, O_NONBLOCK 也在 open 方法中有意义. 这个发生在当这个调用真正阻塞长时间 时; 例如, 当打开(为读存取)一个 没有写者的(尚无)FIFO, 或者存取一个磁盘文件使用 一个悬挂锁. 常常地, 打开一个设备或者成功或者失败, 没有必要等待外部的事件. 有时, 但是, 打开这个设备需要一个长的初始化, 并且你可能选择在你的 open 方法中支持 O_NONBLOCK , 通过立刻返回 -EAGAIN,如果这个标志被设置. 在开始这个设备的初始化进 程之后. 这个驱动可能还实现一个阻塞 open 来支持存取策略, 通过类似于文件锁的方式. 我们将见到这样一个实现在"阻塞 open 作为对 EBUSY 的替代"一节, 在本章后面.

    一些驱动可能还实现特别的语义给 O_NONBLOCK; 例如, 一个磁带设备的 open 常常阻塞 直到插入一个磁带. 如果这个磁带驱动器使用 O_NONBLOCK 打开, 这个 open 立刻成功, 不管是否介质在或不在.

    只有 read, write, 和 open 文件操作受到非阻塞标志影响.

  • 相关阅读:
    BEC listen and translation exercise 44
    中译英12
    BEC listen and translation exercise 43
    中译英11
    BEC listen and translation exercise 42
    中译英10
    BEC listen and translation exercise 41
    中译英9
    BEC listen and translation exercise 40
    中译英8
  • 原文地址:https://www.cnblogs.com/fanweisheng/p/11141836.html
Copyright © 2011-2022 走看看