Socket 同步⁄异步 io 以及阻塞⁄非阻塞的概念理解
Socket 同步/异步 IO 以及阻塞/非阻塞的概念理解
阻塞/非阻塞 IO
阻塞:该函数在未得到预想结果,会阻塞进程,直到函数完成。
非阻塞:该函数在未得到预想结果,不会阻塞进程,而是会返回失败的错误,此时用户可以进行其他工作,之后用户可以多次调用该函数,直到成功。
一般意义上的同步/异步
-
同步:两个事件 A、B 必须以一定顺序执行,如 B 执行前,A 必须已执行,若 A 未执行完成,则 B 必须阻塞等待。
Linux 通常使用 Mutex 完成这样的同步要求。
-
异步:两个事件没有固定的执行顺序要求。
Linux Socket IO 上的同步/异步
当同步/异步概念来到 Socket IO 时,需要注意它是针对内核 IO 操作的,发生在用户调用 IO 操作的系统调用时,不明白这一点,就可能会造成误解,误以为认为它是一个更为宏观的概念。
IO 操作是什么
数据:硬件->内核->用户态;
或
数据:用户态->内核->内核的过程。
如 socket 的读 IO 操作即是:
IO 操作即内核从 socket 读取数据,保存到内核缓冲区,然后将数据从内核缓冲区拷贝到用户态的缓冲区的过程。
理解同步/异步 IO
-
同步 IO
开始 IO 操作后,整个 IO 过程中用户会一直阻塞,直到完成。
-
异步 IO
开始 IO 操作后,用户可以从调用的函数中立即返回,等到数据拷贝到用户态缓冲区完成后,用户会收到通知的 signal。
由此看来,同步和异步的区别在于,实际的 IO 操作是怎么进行的,即是在是函数立即返回的非阻塞模式中,若函数返回的是错误,其实 IO 操作还并未执行,真正执行 IO 时,还是阻塞的。
IO 操作的分类
我们平时熟知的 socket 操作大多是同步 IO:
-
同步:read/write/recvfrom/sendto
-
异步: aio_read
关于 select/poll/epoll + 非阻塞:
仍然是同步 IO,在实际进行 IO 操作时,是阻塞式的。
引经据典
Richard Stevens 在 UNPv1 中是这样描述同步和非同步的:
POSIX defines these two terms as follows:
- A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes.
- An asynchronous I/O operation does not cause the requesting process to be blocked.