33.Linux/Unix 系统编程手册(上) -- 线程:更多细节

1.线程栈
	创建线程时,每个线程都有属于自己的线程栈,且大小固定。在Linux/x86-32架构上,
  除主线程外的所有线程,其栈大小均为2MB(64位下可能是 32MB),为了应对栈的增长,主线程的栈可能大一些。
    在x86-32系统中,用户可访问的虚拟地址空间是3G,而2MB的缺省栈大小意味着最多可以创建1500个线程。

2.线程与信号
	pthread_sigmask();
	pthread_kill();
	pthread_sigqueue();
	sigwait();

3.线程和进程控制
	线程和 exec():
		只要任何线程调用了 exec, 调用程序将被完全替换。除了调用 exec 的线程外,其他线程都立即消失。

	线程和 fork():
		当多线程调用 fork 时,仅会将发起调用的线程复制到子进程中,其他线程均在子进程中消失。
		phtread_atfork();

	线程和 exit() :
		如果任何线程调用了 exit(),或者主线程执行了 return。那么所有线程将消失。

4.线程实现模型
	这3种模式的差异主要集中在线程如何与内核调度实体(KSE)相映射。

	1.多对一(M:1)实现(用户级线程)
		在 M:1 线程实现中,关乎线程创建,调度以及同步(互斥量的锁定,条件变量的等待等)的所有细节全部由进程内用户空间的
	  线程库来实现。对于进程中存在多个线程,内核一无所知。
	  
	  优点:
	    M:1 实现的优势不多,其中最大的有点在于,许多线程的操作(例如线程的创建,终止,线程上下文的切换,互斥量以及条件变量的操作)
	  速度都很快,因为无需切换到内核模式。此外,由于线程库无需内核支持,所以移植比较容易一些。

	  缺点:
	    1.当一线线程发起系统调用(如 read())时,控制由用户空间的线程库转交给内核。这就意味着,如果read()遭到阻塞,那么所有的线程都会
	      被阻塞。
	    2.内核无法知道进程中的这些线程。因为内核并不知晓进程中存在这些线程,也就无法再多处理平台上将各个线程调度给不同的处理器。另外,
	      也不可能将一进程的优先级调整为高于其他进程中的线程,这是没有意义的,因为对线程的调度完全在进程中处理。

	2.一对一(1:1)实现(内核级线程)
		在 1:1 线程实现中,每个线程映射一个单独的 KSE。内核分别对每个线程做调度处理,线程的同步操作通过内核系统调用实现。
		1:1 实现消除了 M:1 的弊端。遭阻塞的系统调用不会导致进程的所有线程被阻塞,在多处理平台上,内核还可以将进程中的多个线程调度到不同CPU上。
		不过,因为需要切换内核模式,所以诸如线程创建,上下文切换,同步操作就要慢一些。另外,为每个线程分别维护一个 KSE也需要开销,如果应用程序
	  包含大量线程,则可能对内核调度器造成严重负担,降低系统的整体性能。
	    尽管有这些缺点,1:1 还是优于 M:1 实现。 LinuxThreads 和 NPTL 都采用 1:1 模型。

	3.多对多(M:N)实现(两级模型)
		M:N 实现皆在结合 1:1 和 M:1 的优点,避免缺点。
		问题在于,过于复杂。

5.Linux Posix 线程的实现
	1.LinuxThreads(淘汰)
		线程的创建用了 clone(), 还会附加创建一个管理线程.
	2.NPTL
	3.NGPT(淘汰)

	getonf GNU_LIBPTHREAD_VERSION //查看用了哪个线程库
	
	

猜你喜欢

转载自blog.csdn.net/enlyhua/article/details/82929680