返回信息流《现代操作系统》进程线程那一章,在讲用户级线程的缺点时,有一句话看不懂(加粗),不知道有没有人可以帮忙解释一下。
如下:
Another, and probably the most devastating argument against user-level threads, is that programmers generally want threads precisely in applications where the threads block often, as, for example, in a multithreaded Web server. These threads are constantly making system calls. Once a trap has occurred to the kernel to carry out the system call, it is hardly any more work for the kernel to switch threads if the old one has blocked, and having the kernel do this eliminates the need for constantly making select system calls that check to see if read system calls are safe. For applications that are essentially entirely CPU bound and rarely block, what is the point of having threads at all? No one would seriously propose computing the first n prime numbers or playing chess using threads because there is nothing to be gained by doing it that way.
中文版的翻译:
再者,也许反对用户级线程的最大负面争论意见是,程序员通常在经常发生阻塞的应用中才希望使用多个线程。例如,在多线程Web服务器里,这些线程持续地进行系统调用,而一旦发生内核陷阱进行系统调用,如果原有的线程已经阻塞,就很难让内核进行线程的切换,如果要让内核消除这种情形,就要持续进行select系统调用,以便检查read系统调用是否安全。对于那些基本上是CPU密集型而且极少有阻塞的应用程序而言,使用多线程的目的又何在呢?由于这样的做法并不能得到任何益处,所以没有人会真正提出使用多线程来计算前n个素数或者下象棋等这一类工作。
这是一条镜像帖。来源:北邮人论坛 / windows / #122199同步于 2014/9/10
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Windows机器人发帖
关于用户级线程的最大缺点
xiaobing307
2014/9/10镜像同步6 回复
订阅后,新回复会通过你的通知中心匿名送达。
6 条回复
在 IMHO 的前提下:
内核实现的多线程,在当前线程进行阻塞的系统调用(比如 HTTP 服务器在监听新请求),会自动被挂起,调度器执行新的线程。
如果是用户模式实现的多线程(似乎叫 Fiber),多个用户模式线程在调度上确是同一个内核线程,任何一个用户模式线程的阻塞系统调用会阻塞被绑定在同一个内核线程的其他用户线程。所以其他原本可以执行的用户线程却被挂起了。
那么为了防止这种情况发生,可以让内核使用非阻塞调用,但是这从各个角度看都很不科学。另一个方法,就是让用户模式的调度器在执行系统调用前,使用 select 查询当前系统调用会不会阻塞。如果会阻塞,就不发出系统调用,直接调度到另一个 ready 的用户线程。(好坑爹啊……)
下面是原文,可能有帮助。另外,如果还有问题,可以微信( @我的id ) / QQ( 我的id@gmail.com ) 我。
The system calls could all be changed to be nonblocking (e.g., a read on the keyboard would just return 0 bytes if no characters were already buffered), but requiring changes to the operating system is unattractive. Besides, one of the arguments for user-level threads was precisely that they could run with existing operating systems. In addition, changing the semantics of read will require changes to many user programs.
Another alternative is possible in the event that it is possible to tell in advance if a call will block. In some versions of UNIX, a system call, select, exists, which allows the caller to tell whether a prospective read will block. When this call is present, the library procedure read can be replaced with a new one that first does a select call and then only does the read call if it is safe (i.e., will not block). If the read call will block, the call is not made. Instead, another thread is run. The next time the run-time system gets control, it can check again to see if the read is now safe. This approach requires rewriting parts of the system call library, is inefficient and inelegant, but there is little choice. The code placed around the system call to do the checking is called a jacket or wrapper.
感谢~~~
调用read之前先select,如果会阻塞就不调用,换另一个线程跑,过一会再select。
这样不是应该能解决read会阻塞整个进程的问题么?为啥那段话又说这样不行呢?
if the old one has blocked,不是先调用select应该不会block么?
【 在 wmzhere 的大作中提到: 】
: 在 IMHO 的前提下:
: 内核实现的多线程,在当前线程进行阻塞的系统调用(比如 HTTP 服务器在监听新请求),会自动被挂起,调度器执行新的线程。
: 如果是用户模式实现的多线程(似乎叫 Fiber),多个用户模式线程在调度上确是同一个内核线程,任何一个用户模式线程的阻塞系统调用会阻塞被绑定在同一个内核线程的其他用户线程。所以其他原本可以执行的用户线程却被挂起了。
: ...................
还是在 IMHO 的前提下:
> 调用read之前先select,如果会阻塞就不调用,换另一个线程跑,过一会再select。
> 这样不是应该能解决read会阻塞整个进程的问题么?为啥那段话又说这样不行呢?
如果是这样,每一个可能引起阻塞的系统调用,都需要 select 一下,这样最终还是要进行大量的用户模式和内核模式的切换,失掉了用户模式线程的优势。
> if the old one has blocked,不是先调用select应该不会block么?
额…我还是重新说一下吧。就是内核在阻塞内核模式线程并调度到其他线程的代价很小(就是你引用的那句话的意思)。而用户模式线程为了防止其他被绑定的线程被阻塞,需要大量的 select 。所以内核线程减少了 select 调用。
来自「北邮人论坛手机版」