阻塞和忙等之间有什么不同?

11

我知道Busy Waiting的实现方式。它是一个无限循环,像这样:

//main thread
while (true) {
    msg = msgQueue.next();
    msg.runnable.run();
}

//....msg queue
public Message next() {
    while (true) {
        if (!queue.isEmpty()) {
            return queue.dequeue();
        }
    }
}

因此,“next()”方法看起来像是被阻塞了,实际上它一直在运行。 这在书中被称为“忙等待(busy waiting)”。

那么,“进程阻塞”是什么?它的实现细节是什么? 是否也是一个死循环,或者是其他的机制,例如信号机制?

例如: cat xxx | grep "abc"

进程“cat”读取文件并将它们输出。

进程“grep”等待从“cat”获得输入。
所以在“cat”输出数据之前,“grep”应该被阻塞,等待输入然后继续执行。 关于这种“阻塞”的细节,是一个死循环一直读取输入流吗?还是真正停止运行,等待一个信号唤醒它再次执行?


大家好,现在我知道了什么是不同的:繁忙等待是一个循环,CPU将一直执行它,而阻塞是一种内核/操作系统控制,它不会浪费CPU资源。 - krosshj
2个回答

16

区别基本上在于进程发生了什么:

1. 忙等待(Busy Waiting)

忙等待的进程基本上是不断运行的,询问“我们到了吗?我们到了吗?现在怎样,我们到了吗?” 这个问题会消耗100%的CPU周期:

bool are_we_there = false;
while(!are_we_there)
{
   // ask if we're there (without blocking)
    are_we_there = ask_if_we_are_there();
}

2. 被阻塞的进程(或者阻塞其他进程的进程)

被阻塞的进程被操作系统暂停,并将在等待的数据可用时自动收到通知。这需要操作系统的协助才能实现。

例如,一个进程正在等待长时间运行的I/O操作或等待计时器到期:

// use a system call to create a waitable timer
var timer = CreateWaitableTime()

// use another system call that waits on a waitable object
WaitFor(timer);  // this will block the current thread until the timer is signaled

// .. some time in the future, the timer might expire and it's object will be signaled
//    causing the WaitFor(timer) call to resume operation

更新

等待对象在操作系统级别上可能以不同的方式实现,但通常它可能是硬件定时器、中断和由客户端代码向操作系统注册的可等待对象列表的组合。当中断发生时,操作系统的中断处理程序被调用,该程序将依次扫描与该事件相关联的任何可等待对象,并调用某些回调函数,进而最终发出可等待对象(将其置于已发信号状态)。这只是一种简化,但如果您想了解更多信息,可以阅读有关中断和硬件定时器的内容。


嗯...操作系统怎么做? - krosshj

0
当你说“进程被阻塞”时,实际上是指“线程被阻塞”,因为这些是唯一可以获得CPU时间的可调度实体。当一个线程在忙等待时,在循环中浪费CPU时间。当一个线程被阻塞时,系统调用内核代码看到数据或锁不可用,因此将该线程标记为等待状态。然后跳转到调度程序,选择另一个准备好执行的线程。这样一个阻塞系统调用中的代码可能如下所示:
100:    if (data_available()) {
101:        return;
102:    } else {
103:        jump_to_scheduler();
104:    }

稍后线程被重新调度并从第100行重新启动,但它立即进入else分支并再次离开CPU。当数据可用时,系统调用最终返回。

不要逐字翻译,这只是我根据对操作系统的了解所做的猜测,但你应该能够理解。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接