阻塞操作: 执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再进行操作,被挂起的进程进入休眠状态,从调度器的运行队列中移除,直到等待条件满足后再次运行。
非阻塞操作: 执行设备操作时,若不能获得资源,并不挂起,它或者放弃,或者不停地查询,直到可进行操作为止。
1. 阻塞了的进程要确保有一个地方能唤醒它,唤醒阻塞进程的操作一般是在中断里完成,因为硬件资源获得时一般伴随着硬件中断。
2. 驱动中通过等待队列来实现阻塞进程的唤醒。
3. 非阻塞程序实例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #include <errno.h> char buffer[4096]; int main(int argc, char **argv) { int delay = 1, n, m = 0; if (argc > 1) delay=atoi(argv[1]); fcntl(0, F_SETFL, fcntl(0,F_GETFL) | O_NONBLOCK); /* set stdin nonblock*/ fcntl(1, F_SETFL, fcntl(1,F_GETFL) | O_NONBLOCK); /* set stdout nonblock*/ while (1) { n = read(0, buffer, 4096); if (n >= 0) m = write(1, buffer, n); if ((n < 0 || m < 0) && (errno != EAGAIN)) break; printf("coming here "); sleep(delay); } perror(n < 0 ? "stdin" : "stdout"); exit(1); }
分析:通过 fcntl() 设置对标准输入及输出的访问为非阻塞访问。程序运行过程中,如果没有输入数据,则由于 read() 和 write() 调用不阻塞屏幕将打印 "coming here"。
4. 阻塞程序实例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #include <errno.h> char buffer[4096]; int main(int argc, char **argv) { int delay = 1, n, m = 0; if (argc > 1) delay=atoi(argv[1]); // fcntl(0, F_SETFL, fcntl(0,F_GETFL) | O_NONBLOCK); /* set stdin nonblock*/ // fcntl(1, F_SETFL, fcntl(1,F_GETFL) | O_NONBLOCK); /* set stdout nonblock*/ while (1) { n = read(0, buffer, 4096); if (n >= 0) m = write(1, buffer, n); if ((n < 0 || m < 0) && (errno != EAGAIN)) break; printf("coming here "); sleep(delay); } perror(n < 0 ? "stdin" : "stdout"); exit(1); }
分析:去掉 fcntl() 设置非阻塞访问的语句,则是阻塞访问。程序运行过程中,由于 read() 的阻塞,导致每次输入完成后都在 read() 调用的地方暂停等待输入。