阻塞操作: 执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再进行操作,被挂起的进程进入休眠状态,从调度器的运行队列中移除,直到等待条件满足后再次运行。

非阻塞操作: 执行设备操作时,若不能获得资源,并不挂起,它或者放弃,或者不停地查询,直到可进行操作为止。

1. 阻塞了的进程要确保有一个地方能唤醒它,唤醒阻塞进程的操作一般是在中断里完成,因为硬件资源获得时一般伴随着硬件中断。

2. 驱动中通过等待队列来实现阻塞进程的唤醒。

3. 非阻塞程序实例:

#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\n");
        sleep(delay);
    }
    perror(n < 0 ? "stdin" : "stdout");
    exit(1);
}
View Code

 分析:通过 fcntl() 设置对标准输入及输出的访问为非阻塞访问。程序运行过程中,如果没有输入数据,则由于 read() 和 write() 调用不阻塞屏幕将打印 "coming here"。

4. 阻塞程序实例:

#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\n");
        sleep(delay);
    }
    perror(n < 0 ? "stdin" : "stdout");
    exit(1);
}
View Code

 分析:去掉 fcntl() 设置非阻塞访问的语句,则是阻塞访问。程序运行过程中,由于 read() 的阻塞,导致每次输入完成后都在 read() 调用的地方暂停等待输入。