在futex之前,如何在Linux中停放和唤醒线程/进程? [英] How are threads/processes parked and woken in Linux, prior to futex?

查看:147
本文介绍了在futex之前,如何在Linux中停放和唤醒线程/进程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Linux中没有futex系统调用之前,诸如pthreads的线程库使用了哪些底层系统调用来阻塞/休眠线程,并随后将这些线程从用户区唤醒?

Before the futex system calls existed in Linux, what underlying system calls were used by threading libraries like pthreads to block/sleep a thread and to subsequently wake those threads from userland?

例如,如果某个线程尝试获取互斥量,则userland实现将阻塞该线程(可能在较短的旋转间隔之后),但是我找不到用于此目的的系统调用(futex除外)这是相对较新的作品.

For example, if a thread tries to acquire a mutex, the userland implementation will block the thread (perhaps after a short spinning interval), but I can't find the syscalls that are used for this (other than futex which are a relatively recent creation).

推荐答案

在futex和当前用于Linux的pthread NPTL(需要内核2.6及更高版本)的当前实现之前,还有另外两个带有POSIX Thread API的Linux线程库: linuxthreads 和NGPT(其中内置实现在 futex之上的类似pthread的API +克隆).而且Gnu Pth不是线程库,它是具有用户级线程"切换的单进程线程.

Before futex and current implementation of pthreads for Linux, the NPTL (require kernel 2.6 and newer), there were two other threading libraries with POSIX Thread API for Linux: linuxthreads and NGPT (which was based on Gnu Pth. LinuxThreads was the only widely used libpthread for years (and it can still be used in some strange & unmaintained micro-libc to work on 2.4; other micro-libc variants may have own builtin implementation of pthread-like API on top of futex+clone). And Gnu Pth is not thread library, it is single process thread with user-level "thread" switching.

您应该知道,当我们检查时,有几个线程模型内核是否知道某些或所有用户线程(在向程序添加线程时可以使用多少个CPU内核;拥有线程的成本/可以启动多少个线程)?模型命名为M:N,其中M是用户空间线程号,而N是可由OS内核计划的线程号:

You should know that there are several Threading Models when we check does the kernel knows about some or all of user threads (how many CPU cores can be used with adding threads to the program; what is the cost of having the thread / how many threads may be started). Models are named as M:N where M is userspace thread number and N is thread number schedulable by OS kernel:

  • "1:1"内核级线程"-每个用户空间线程均可由OS内核调度.这是在Linuxthreads,NPTL和许多现代OS中实现的.
  • "N:1"用户级线程"-用户空间线程是由用户空间规划的,它们对于内核都是不可见的,它仅调度一个进程(并且可能仅使用1个CPU内核). Gnu Pth( GNU可移植线程)是它的示例,并且还有许多其他实现一些计算机体系结构.
  • "M:N"混合线程"-OS内核中有一些可见且可调度的实体,但是其中可能有更多的用户空间线程.有时用户空间线程会在内核可见的线程之间迁移.
  • "1:1" ''kernel-level threading'' - every userspace thread is schedulable by OS kernel. This is implemented in Linuxthreads, NPTL and many modern OS.
  • "N:1" ''user-level threading'' - userspace threads are planned by the userspace, they all are invisible to the kernel, it only schedules one process (and it may use only 1 CPU core). Gnu Pth (GNU Portable Threads) is example of it, and there are many other implementations for some computer architectures.
  • "M:N" ''hybrid threading'' - there are some entities visible and schedulable by OS kernel, but there may be more user-space threads in them. And sometimes user-space threads will migrate between kernel-visible threads.

使用1:1模型时,Unix中有许多经典的睡眠机制/API,例如选择/轮询和信号以及 IPC API.我记得, Linuxthreads 为每个线程(具有完全共享的内存)使用了单独的进程,并且特殊的管理器线程"(进程)来模拟一些POSIX线程功能. 维基百科说SIGUSR1/SIGUSR2在Linuxthreads中用于线程之间的一些内部通信,相同的说IBM 同步基元的生成是通过信号来实现的.例如,线程阻塞直到被信号唤醒为止."另请检查项目常见问题解答 http://pauillac.inria.fr/〜xleroy/linuxthreads/faq.html#H.4 有了LinuxThreads,我不能再在程序中使用信号SIGUSR1和SIGUSR2!为什么?"

With 1:1 model there are many classic sleep mechanisms/APIs in Unix like select/poll and signals and other variants of IPC APIs. As I remember, Linuxthreads used separate processes for every thread (with fully shared memory) and there was special manager "thread" (process) to emulate some POSIX thread features. Wikipedia says that SIGUSR1/SIGUSR2 were used in Linuxthreads for some internal communication between threads, same says IBM "The synchronization of primitives is achieved by means of signals. For example, threads block until awoken by signals.". Check also the project FAQ http://pauillac.inria.fr/~xleroy/linuxthreads/faq.html#H.4 "With LinuxThreads, I can no longer use the signals SIGUSR1 and SIGUSR2 in my programs! Why?"

LinuxThreads的内部操作需要两个信号. 一个用于挂起和重新启动在互斥,条件或信号量操作中阻塞的线程.另一个用于线程取消. 在``旧''内核(2.0和2.1之前的内核)上,只有32个可用信号,内核保留所有信号,但只有两个:SIGUSR1和SIGUSR2.因此,LinuxThreads别无选择,只能使用这两个信号.

LinuxThreads needs two signals for its internal operation. One is used to suspend and restart threads blocked on mutex, condition or semaphore operations. The other is used for thread cancellation. On ``old'' kernels (2.0 and early 2.1 kernels), there are only 32 signals available and the kernel reserves all of them but two: SIGUSR1 and SIGUSR2. So, LinuxThreads has no choice but use those two signals.

使用"N:1"模型线程可以调用某些阻塞的系统调用并阻塞所有内容(某些库可能会将某些阻塞的系统调用转换为异步,或使用某些

With "N:1" model thread may call some blocking syscall and block everything (some libraries may convert some blocking syscalls into async, or use some SIGALRM or SIGVTALRM magic); or it may call some (very) special internal threading function which will do user-space thread switching by rewriting machine state register (like switch_to in linux kernel, save IP/SP and other regs, restore IP/SP and regs of other thread). So, kernel does not wake any user thread directly from userland, it just schedules whole process; and user space scheduler implement thread synchronization logic (or just calls sched_yield or select when there is no threads to work).

使用M:N模型时,事情非常复杂...对NGPT不太了解...

With M:N model things are very complicated... Don't know much about NGPT... There is one paragraph about NGPT in POSIX Threads and the Linux Kernel, Dave McCracken, OLS2002,330 page 5

正在开发一个名为NGPT的新pthread库.该库基于GNU Pth库,它是一个M:1库. NGPT通过使用多个Linux任务扩展了Pth,从而创建了M:N库.它试图保留Pth的pthread兼容性,同时还使用多个Linux任务来进行并发,但是由于Linux线程模型的根本差异,这项工作受到了阻碍.目前,NGPT库在阻塞系统调用周围使用非阻塞包装程序,以避免 阻塞内核.

There is a new pthread library under development called NGPT. This library is based on the GNU Pth library, which is an M:1 library. NGPT extends Pth by using multiple Linux tasks, thus creating an M:N library. It attempts to preserve Pth’s pthread compatibility while also using multiple Linux tasks for concurrency, but this effort is hampered by the underlying differences in the Linux threading model. The NGPT library at present uses non-blocking wrappers around blocking system calls to avoid blocking in the kernel.

一些论文和帖子: POSIX线程和Linux内核,Dave McCracken,OLS2002,330 有关NPTL 0.1的LWN帖子

futex系统调用在所有同步中被广泛使用 原语和其他需要某种形式的地方 同步. futex机制足够通用以支持 几乎没有标准的POSIX同步机制 努力. ... Futex还允许执行进程间 同步原语,这是旧版本中非常错过的​​功能 LinuxThreads实现(jbj!).

The futex system call is used extensively in all synchronization primitives and other places which need some kind of synchronization. The futex mechanism is generic enough to support the standard POSIX synchronization mechanisms with very little effort. ... Futexes also allow the implementation of inter-process synchronization primitives, a sorely missed feature in the old LinuxThreads implementation (Hi jbj!).

NPTL设计pdf :

5.5同步基元 同步原语的实现,例如互斥体,读写 锁,条件变量,信号量和障碍需要某种形式的内核 支持.繁忙等待不是一种选择,因为线程可以具有不同的优先级(除了浪费CPU周期之外).相同的参数排除了计划收益率的排他性使用. 信号是旧实现的唯一可行解决方案.线程将在内核中阻塞,直到被信号唤醒为止.该方法在速度和可靠性方面存在严重缺陷,这些缺陷是由虚假唤醒和应用中信号处理质量的下降所引起的. 幸运的是,内核中添加了一些新功能来实现各种功能 同步原语集:futex [Futex].基本原理很简单,但 功能强大,足以适应各种用途.调用者可以阻止内核 并因中断或超时而被明确唤醒.

5.5 Synchronization Primitives The implementation of the synchronization primitives such as mutexes, read-write locks, conditional variables, semaphores, and barriers requires some form of kernel support. Busy waiting is not an option since threads can have different priorities (beside wasting CPU cycles). The same argument rules out the exclusive use of sched yield. Signals were the only viable solution for the old implementation. Threads would block in the kernel until woken by a signal. This method has severe drawbacks in terms of speed and reliability caused by spurious wakeups and derogation of the quality of the signal handling in the application. Fortunately some new functionality was added to the kernel to implement all kinds of synchronization primitives: futexes [Futex]. The underlying principle is simple but powerful enough to be adaptable to all kinds of uses. Callers can block in the kernel and be woken either explicitly, as a result of an interrupt, or after a timeout.

这篇关于在futex之前,如何在Linux中停放和唤醒线程/进程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆