Bo2SS

Bo2SS

2 Blocking and Non-blocking IO

  • Image

Course Content#

Understand the true meaning and differences between the two, and be able to answer the above questions.

Literal Meanings of Both#

Going to Work

  • Blocking: There is traffic on the way to work, wait or use other methods, in short, you have to go to work.
  • Non-blocking: There is traffic on the way to work, just don’t go.

Mom Asked to Buy Soy Sauce

  • Blocking: There is no soy sauce, ask mom if I should get something else, or buy something else.
  • Non-blocking: There is no soy sauce, just don’t buy it.

Let Xiao Ming Write a Report

  • Blocking: Wait for Xiao Ming to finish writing.
  • Non-blocking: No need to wait for Xiao Ming to write, inform the result later [ask Xiao Ming myself - synchronous / Xiao Ming tells me proactively - asynchronous].

Boiling Water

Introduction#

  • Review O_NONBLOCK in the open function.
    • image-20210120101248947
    • Everything is a file, so everything can be blocking/non-blocking.
  • Analyze the process of writing a file.
    • Open → write → close.
    • Among them, write is a system call, the specific process is as follows:
      • Data → kernel → disk: The kernel copies the data and places it in the buffer [block buffer]. When flushing the buffer, it schedules the IO device, finds the inode and block, and writes the data to the disk.
      • NON_BLOCK sets the user mode [data → kernel or kernel → data] process.
        • Most of the blocking occurs when taking data out from the kernel.
      • The process from kernel → disk is actually blocking.
        • To allow upper-level applications to quickly return the write status, the kernel writes the data to the disk, which ordinary users do not need to perceive.
        • After the kernel copies the data, the program returns, and ordinary users think the write was successful, but the data is likely still in the buffer [Buffered IO].

fcntl#

Operate on file descriptors [can make files non-blocking].

  • man fcntl
  • Prototype
    • Image
    • fd: file descriptor. The most common file descriptors: 0, 1, 2.
    • cmd: operation mode.
    • ... /* arg */
      • Variable parameters.
      • arg indicates that this parameter is the parameter of the previous parameter [cmd], its meaning depends on cmd.
  • Description
    • Image
    • cmd in parentheses indicates whether there are variable parameters, at most one.
    • The variable parameter type is generally int, using macro definitions, essentially a bitmask, changing the state through bitwise operations.
    • Among them, there is a category of cmd: related to [file status flags].
      • Image
      • You can obtain or set the file status [such as O_NONBLOCK].
  • Return Value
    • Image
    • Observe the return value, consider the judgments in the program.
    • Errors return -1, successful setting operations return 0.

select#

Synchronous I/O multiplexing [interface].

  • man select
  • Prototype
    • Image
    • nfds: number of file descriptors.
    • fd_set: set of file descriptors.
      • Readable, writable, exceptions.
      • Implemented using arrays at the bottom.
    • timeout: time interval.
    • Four macros are used to operate on the set, see below.
  • Description
    • Image
    • Allows the program to monitor multiple file descriptors, waiting for one or more file descriptors' I/O operations to be "ready".
      • ready: ready, can perform corresponding IO operations on the file, such as non-blocking reads or sufficiently small writes.
    • The number of file descriptors that can be monitored is less than FD_SETSIZE [generally 1024].
    • Image
    • When exiting, each file descriptor set will be modified, leaving only the file descriptors whose status has changed, serving as an indication.
      • Therefore, if select is used in a loop, each set needs to be re-initialized before each call to select.
    • The set can be NULL, indicating that no files are being monitored in this type of event.
    • Macros for operating on the set:
      • FD_ZERO: clear a set.
      • FD_SET: add a file descriptor to a set.
      • FD_CLR: remove a file descriptor from a set.
      • FD_ISSET: determine which set a file descriptor belongs to, can be used after select returns, as the set has been modified.
    • The value of nfds is the maximum number of file descriptors in the three sets plus one.
      • The index of file descriptors starts from 0.
    • Image
    • struct timeval timeout
      • Specifies the time interval for select to block while waiting for each file descriptor to be ready.
        • Here, blocking means purely blocking, not blocking I/O.
        • [Personal understanding] The synchronization in synchronous I/O multiplexing is reflected here.
      • Three conditions for stopping blocking:
        • A file descriptor is ready.
        • Signal interruption [kill].
        • Timeout.
      • The time interval is not precise, it is difficult to achieve true precision.
        • System clock granularity, kernel scheduling delay.
      • The timeval structure has two members: seconds, microseconds.
        • If both are 0, it will return immediately, can be used for polling.
        • If NULL, it will wait indefinitely.
      • Image
      • The timeout update function only works on Linux.
      • For compatibility, try not to use it, and use more common functions.
  • Return Value
    • Image
    • Returns the number of file descriptors [ready] in all sets at that time.
      • Based on the number, use the macro FD_ISSET to inquire about the status change of all file descriptors.
      • 0: Time is up, and no interesting events occurred.
      • -1: error, and sets errno; at this time, the set will not change, and timeout becomes undefined.

[PS]

  • select → poll → epoll, increasingly advanced.
    • man poll
    • man epoll
    • All perform similar tasks to select.

Code Demonstration#

Implementing Interfaces to Make Files Non-blocking and Blocking#

  • common.h
    • Image
    • Two interfaces.
  • head.h
    • Image
    • The order of header files matters, generally placing your own project's header files at the end.
    • Image
    • Reference The Path and Order of #include——Google C++ Programming Style.
  • common.c
    • Image
    • When setting flags, do not change the original flags.
    • 👉 First get, then add/remove flags using bitwise OR / AND.

Non-blocking File Descriptor 0#

  • Image
  • Common files 0, 1, 2 do not need to be opened manually.
    • These three files are automatically opened when creating a process.
    • They are inherited.
  • Compile command: gcc 1.test.c ../common/common.c -I ../common/
    • Remember to add the common.c file during compilation.
  • After setting file descriptor 0 to non-blocking, the key change is that reading and writing of file descriptor 0 becomes non-blocking.
    • ① No sleep.
      • Image
      • scanf reads file descriptor 0.
      • But there is no data, it proceeds directly without blocking to wait for data in file descriptor 0.
    • ② With sleep.
      • Image
      • During the 5 seconds of sleep, input data in the terminal [+enter, line buffering].
        • The process pauses, not occupying CPU.
        • But the standard input stream remains open, and the data entered by the user in the terminal will be passed to file descriptor 0 by the kernel.
          • The file is maintained by the kernel, and during the sleep process, the kernel can write data to the file.
      • After sleep ends, scanf reads the data from file descriptor 0.
    • 【Clarification】 Non-blocking refers to a certain object, such as file descriptor 0; not to a certain function or operation.
  • [PS]
    • Blocking: may waste time.
    • Non-blocking: may waste resources.
      • Generally used in large programs and high-concurrency servers.

Select on File Descriptor 0#

  • Copied from the man manual — EXAMPLE in man select.
  • Image
  • select can perceive the arrival of I/O.
  • Running effect.
    • image-20210120101405659
    • Input ls in the terminal, and after the program ends, ls will still execute.
    • Because the content of the buffer has not been taken away [like scanf], it is ultimately taken by zsh.
  • select was blocking during the monitored time interval.
    • In all user-level programs, so-called blocking means sleeping [sleep()].
    • Blocking termination conditions: ready, signal interruption, timeout.
  • [Extended Application]
    • Set a timer for blocking places, use default values on timeout.
      • Avoid blocking for too long due to exceptional situations [SSH host unreachable...].
      • More user-friendly.

Additional Knowledge Points#

  • There are many ways to perceive I/O, among which the kernel fully knows the arrival of IO.

Points to Consider#

Tips#

  • Course Preview: Multiprocessing [fork...].
  • Consider the implementation of cp.
    • Examine file read and write operations.
    • Must be blocking.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.