﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-mysileng-随笔分类-linux多线程专题</title><link>http://www.cppblog.com/mysileng/category/20266.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 18 Dec 2012 06:06:56 GMT</lastBuildDate><pubDate>Tue, 18 Dec 2012 06:06:56 GMT</pubDate><ttl>60</ttl><item><title>多进程与多线程（八）--Linux 线程实现机制分析 (转)</title><link>http://www.cppblog.com/mysileng/archive/2012/12/18/196408.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 18 Dec 2012 05:57:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/18/196408.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196408.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/18/196408.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196408.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196408.html</trackback:ping><description><![CDATA[<p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N10037" style="word-wrap: break-word; color: #63401b; ">转自http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/</a><span style="word-wrap: break-word; line-height: 1.5; ">（杨沙洲</span>&nbsp;(pubb@163.net)国防科技大学计算机学院<a name="N10037" style="word-wrap: break-word; color: #63401b; ">） &nbsp;</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N10037" style="word-wrap: break-word; color: #63401b; ">一.基础知识：线程和进程</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">按照教科书上的定义，进程是资源管理的最小单位，线程是程序执行的最小单位。在操作系统设计上，从进程演化出线程，最主要的目的就是更好的支持SMP以及减小（进程/线程）上下文切换开销。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">无论按照怎样的分法，一个进程至少需要一个线程作为它的指令执行体，进程管理着资源（比如cpu、内存、文件等等），而将线程分配到某 个cpu上执行。一个进程当然可以拥有多个线程，此时，如果进程运行在SMP机器上，它就可以同时使用多个cpu来执行各个线程，达到最大程度的并行，以 提高效率；同时，即使是在单cpu的机器上，采用多线程模型来设计程序，正如当年采用多进程模型代替单进程模型一样，使设计更简洁、功能更完备，程序的执 行效率也更高，例如采用多个线程响应多个输入，而此时多线程模型所实现的功能实际上也可以用多进程模型来实现，而与后者相比，线程的上下文切换开销就比进 程要小多了，从语义上来说，同时响应多个输入这样的功能，实际上就是共享了除cpu以外的所有资源的。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">针对线程模型的两大意义，分别开发出了核心级线程和用户级线程两种线程模型，分类的标准主要是线程的调度者在核内还是在核外。前者更利 于并发使用多处理器的资源，而后者则更多考虑的是上下文切换开销。在目前的商用系统中，通常都将两者结合起来使用，既提供核心线程以满足smp系统的需 要，也支持用线程库的方式在用户态实现另一套线程机制，此时一个核心线程同时成为多个用户态线程的调度者。正如很多技术一样，"混合"通常都能带来更高的 效率，但同时也带来更大的实现难度，出于"简单"的设计思路，Linux从一开始就没有实现混合模型的计划，但它在实现上采用了另一种思路的"混合"。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">在线程机制的具体实现上，可以在操作系统内核上实现线程，也可以在核外实现，后者显然要求核内至少实现了进程，而前者则一般要求在核内 同时也支持进程。核心级线程模型显然要求前者的支持，而用户级线程模型则不一定基于后者实现。这种差异，正如前所述，是两种分类方式的标准不同带来的。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">当核内既支持进程也支持线程时，就可以实现线程-进程的"多对多"模型，即一个进程的某个线程由核内调度，而同时它也可以作为用户级线 程池的调度者，选择合适的用户级线程在其空间中运行。这就是前面提到的"混合"线程模型，既可满足多处理机系统的需要，也可以最大限度的减小调度开销。绝 大多数商业操作系统（如Digital Unix、Solaris、Irix）都采用的这种能够完全实现POSIX1003.1c标准的线程模型。在核外实现的线程又可以分为"一对一"、"多对 一"两种模型，前者用一个核心进程（也许是轻量进程）对应一个线程，将线程调度等同于进程调度，交给核心完成，而后者则完全在核外实现多线程，调度也在用 户态完成。后者就是前面提到的单纯的用户级线程模型的实现方式，显然，这种核外的线程调度器实际上只需要完成线程运行栈的切换，调度开销非常小，但同时因 为核心信号（无论是同步的还是异步的）都是以进程为单位的，因而无法定位到线程，所以这种实现方式不能用于多处理器系统，而这个需求正变得越来越大，因 此，在现实中，纯用户级线程的实现，除算法研究目的以外，几乎已经消失了。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">Linux内核只提供了轻量进程的支持，限制了更高效的线程模型的实现，但Linux着重优化了进程的调度开销，一定程度上也弥补了这 一缺陷。目前最流行的线程机制LinuxThreads所采用的就是线程-进程"一对一"模型，调度交给核心，而在用户级实现一个包括信号处理在内的线程 管理机制。Linux-LinuxThreads的运行机制正是本文的描述重点。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N1004F" style="word-wrap: break-word; color: #63401b; ">二.Linux 2.4内核中的轻量进程实现</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">最初的进程定义都包含程序、资源及其执行三部分，其中程序通常指代码，资源在操作系统层面上通常包括内存资源、IO资源、信号处理等部 分，而程序的执行通常理解为执行上下文，包括对cpu的占用，后来发展为线程。在线程概念出现以前，为了减小进程切换的开销，操作系统设计者逐渐修正进程 的概念，逐渐允许将进程所占有的资源从其主体剥离出来，允许某些进程共享一部分资源，例如文件、信号，数据内存，甚至代码，这就发展出轻量进程的概念。 Linux内核在2.0.x版本就已经实现了轻量进程，应用程序可以通过一个统一的clone()系统调用接口，用不同的参数指定创建轻量进程还是普通进 程。在内核中，clone()调用经过参数传递和解释后会调用do_fork()，这个核内函数同时也是fork()、vfork()系统调用的最终实 现：</p><table border="0" cellpadding="0" cellspacing="0" width="100%" style="word-wrap: break-word; color: #000000; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; text-align: start; background-color: #f5f7f8; "><tbody style="word-wrap: break-word; "><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">&lt;linux-2.4.20/kernel/fork.c&gt; int do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size)</td></tr></tbody></table><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">其中的clone_flags取自以下宏的"或"值：</p><table border="0" cellpadding="0" cellspacing="0" width="100%" style="word-wrap: break-word; color: #000000; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; text-align: start; background-color: #f5f7f8; "><tbody style="word-wrap: break-word; "><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">&lt;linux-2.4.20/include/linux/sched.h&gt; #define CSIGNAL 0x000000ff /* signal mask to be sent at exit */ #define CLONE_VM 0x00000100 /* set if VM shared between processes */ #define CLONE_FS 0x00000200 /* set if fs info shared between processes */ #define CLONE_FILES 0x00000400 /* set if open files shared between processes */ #define CLONE_SIGHAND 0x00000800 /* set if signal handlers and blocked signals shared */ #define CLONE_PID 0x00001000 /* set if pid shared */ #define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */ #define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */ #define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */ #define CLONE_THREAD 0x00010000 /* Same thread group? */ #define CLONE_NEWNS 0x00020000 /* New namespace group? */ #define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD)</td></tr></tbody></table><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">在do_fork()中，不同的clone_flags将导致不同的行为，对于LinuxThreads，它使用（CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND）参数来调用clone()创建"线程"，表示共享内存、共享文件系统访问计数、共享文件描述符表，以及共享信号处理方式。本 节就针对这几个参数，看看Linux内核是如何实现这些资源的共享的。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">1.CLONE_VM</strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">do_fork()需要调用copy_mm()来设置task_struct中的mm和active_mm项，这两个 mm_struct数据与进程所关联的内存空间相对应。如果do_fork()时指定了CLONE_VM开关，copy_mm()将把新的 task_struct中的mm和active_mm设置成与current的相同，同时提高该mm_struct的使用者数目 （mm_struct::mm_users）。也就是说，轻量级进程与父进程共享内存地址空间，由下图示意可以看出mm_struct在进程中的地位：</p><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><img alt="" src="http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/1.gif" height="380" border="0" width="567" style="word-wrap: break-word; border: 0px; max-width: 650px; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " />&nbsp;<br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">2.CLONE_FS</strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">task_struct中利用fs（struct fs_struct *）记录了进程所在文件系统的根目录和当前目录信息，do_fork()时调用copy_fs()复制了这个结构；而对于轻量级进程则仅增加 fs-&gt;count计数，与父进程共享相同的fs_struct。也就是说，轻量级进程没有独立的文件系统相关的信息，进程中任何一个线程改变当前 目录、根目录等信息都将直接影响到其他线程。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">3.CLONE_FILES</strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">一个进程可能打开了一些文件，在进程结构task_struct中利用files（struct files_struct *）来保存进程打开的文件结构（struct file）信息，do_fork()中调用了copy_files()来处理这个进程属性；轻量级进程与父进程是共享该结构的，copy_files() 时仅增加files-&gt;count计数。这一共享使得任何线程都能访问进程所维护的打开文件，对它们的操作会直接反映到进程中的其他线程。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">4.CLONE_SIGHAND</strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">每一个Linux进程都可以自行定义对信号的处理方式，在task_struct中的sig（struct signal_struct）中使用一个struct k_sigaction结构的数组来保存这个配置信息，do_fork()中的copy_sighand()负责复制该信息；轻量级进程不进行复制，而仅 仅增加signal_struct::count计数，与父进程共享该结构。也就是说，子进程与父进程的信号处理方式完全相同，而且可以相互更改。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">do_fork()中所做的工作很多，在此不详细描述。对于SMP系统，所有的进程fork出来后，都被分配到与父进程相同的cpu上，一直到该进程被调度时才会进行cpu选择。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">尽管Linux支持轻量级进程，但并不能说它就支持核心级线程，因为Linux的"线程"和"进程"实际上处于一个调度层次，共享一个 进程标识符空间，这种限制使得不可能在Linux上实现完全意义上的POSIX线程机制，因此众多的Linux线程库实现尝试都只能尽可能实现POSIX 的绝大部分语义，并在功能上尽可能逼近。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N100A1" style="word-wrap: break-word; color: #63401b; ">三.LinuxThread的线程机制</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">LinuxThreads是目前Linux平台上使用最为广泛的线程库，由Xavier Leroy (Xavier.Leroy@inria.fr)负责开发完成，并已绑定在GLIBC中发行。它所实现的就是基于核心轻量级进程的"一对一"线程模型，一 个线程实体对应一个核心轻量级进程，而线程之间的管理在核外函数库中实现。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N100AA" style="word-wrap: break-word; color: #63401b; ">1.线程描述数据结构及实现限制</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">LinuxThreads定义了一个struct _pthread_descr_struct数据结构来描述线程，并使用全局数组变量__pthread_handles来描述和引用进程所辖线程。在 __pthread_handles中的前两项，LinuxThreads定义了两个全局的系统线程：__pthread_initial_thread 和__pthread_manager_thread，并用__pthread_main_thread表征 __pthread_manager_thread的父线程（初始为__pthread_initial_thread）。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">struct _pthread_descr_struct是一个双环链表结构，__pthread_manager_thread所在的链表仅包括它一个元素，实际 上，__pthread_manager_thread是一个特殊线程，LinuxThreads仅使用了其中的errno、p_pid、 p_priority等三个域。而__pthread_main_thread所在的链则将进程中所有用户线程串在了一起。经过一系列 pthread_create()之后形成的__pthread_handles数组将如下图所示：</p><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><img alt="图2 __pthread_handles数组结构" src="http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/2.gif" height="251" border="0" width="491" style="word-wrap: break-word; border: 0px; max-width: 650px; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " />&nbsp;<br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">新创建的线程将首先在__pthread_handles数组中占据一项，然后通过数据结构中的链指针连入以__pthread_main_thread为首指针的链表中。这个链表的使用在介绍线程的创建和释放的时候将提到。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">LinuxThreads遵循POSIX1003.1c标准，其中对线程库的实现进行了一些范围限制，比如进程最大线程数，线程私有数 据区大小等等。在LinuxThreads的实现中，基本遵循这些限制，但也进行了一定的改动，改动的趋势是放松或者说扩大这些限制，使编程更加方便。这 些限定宏主要集中在sysdeps/unix/sysv/linux/bits/local_lim.h（不同平台使用的文件位置不同）中，包括如下几 个：</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">每进程的私有数据key数，POSIX定义_POSIX_THREAD_KEYS_MAX为128，LinuxThreads使用 PTHREAD_KEYS_MAX，1024；私有数据释放时允许执行的操作数，LinuxThreads与POSIX一致，定义 PTHREAD_DESTRUCTOR_ITERATIONS为4；每进程的线程数，POSIX定义为64，LinuxThreads增大到 1024（PTHREAD_THREADS_MAX）；线程运行栈最小空间大小，POSIX未指定，LinuxThreads使用 PTHREAD_STACK_MIN，16384（字节）。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N100D0" style="word-wrap: break-word; color: #63401b; ">2.管理线程</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">"一对一"模型的好处之一是线程的调度由核心完成了，而其他诸如线程取消、线程间的同步等工作，都是在核外线程库中完成的。在 LinuxThreads中，专门为每一个进程构造了一个管理线程，负责处理线程相关的管理工作。当进程第一次调用pthread_create()创建 一个线程的时候就会创建（__clone()）并启动管理线程。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">在一个进程空间内，管理线程与其他线程之间通过一对"管理管道（manager_pipe[2]）"来通讯，该管道在创建管理线程之前 创建，在成功启动了管理线程之后，管理管道的读端和写端分别赋给两个全局变量__pthread_manager_reader和 __pthread_manager_request，之后，每个用户线程都通过__pthread_manager_request向管理线程发请求， 但管理线程本身并没有直接使用__pthread_manager_reader，管道的读端（manager_pipe[0]）是作为 __clone()的参数之一传给管理线程的，管理线程的工作主要就是监听管道读端，并对从中取出的请求作出反应。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">创建管理线程的流程如下所示：&nbsp;<br style="word-wrap: break-word; " />（全局变量pthread_manager_request初值为-1）</p><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><img alt="图3 创建管理线程的流程" src="http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/3.gif" height="332" border="0" width="416" style="word-wrap: break-word; border: 0px; max-width: 650px; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " />&nbsp;<br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">初始化结束后，在__pthread_manager_thread中记录了轻量级进程号以及核外分配和管理的线程 id，2*PTHREAD_THREADS_MAX+1这个数值不会与任何常规用户线程id冲突。管理线程作为pthread_create()的调用者 线程的子线程运行，而pthread_create()所创建的那个用户线程则是由管理线程来调用clone()创建，因此实际上是管理线程的子线程。 （此处子线程的概念应该当作子进程来理解。）</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">__pthread_manager()就是管理线程的主循环所在，在进行一系列初始化工作后，进入while(1)循环。在循环中， 线程以2秒为timeout查询（__poll()）管理管道的读端。在处理请求前，检查其父线程（也就是创建manager的主线程）是否已退出，如果 已退出就退出整个进程。如果有退出的子线程需要清理，则调用pthread_reap_children()清理。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">然后才是读取管道中的请求，根据请求类型执行相应操作（switch-case）。具体的请求处理，源码中比较清楚，这里就不赘述了。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N100FB" style="word-wrap: break-word; color: #63401b; ">3.线程栈</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">在LinuxThreads中，管理线程的栈和用户线程的栈是分离的，管理线程在进程堆中通过malloc()分配一个THREAD_MANAGER_STACK_SIZE字节的区域作为自己的运行栈。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">用户线程的栈分配办法随着体系结构的不同而不同，主要根据两个宏定义来区分，一个是 NEED_SEPARATE_REGISTER_STACK，这个属性仅在IA64平台上使用；另一个是FLOATING_STACK宏，在i386等少 数平台上使用，此时用户线程栈由系统决定具体位置并提供保护。与此同时，用户还可以通过线程属性结构来指定使用用户自定义的栈。因篇幅所限，这里只能分析 i386平台所使用的两种栈组织方式：FLOATING_STACK方式和用户自定义方式。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">在FLOATING_STACK方式下，LinuxThreads利用mmap()从内核空间中分配8MB空间（i386系统缺省的最 大栈空间大小，如果有运行限制（rlimit），则按照运行限制设置），使用mprotect()设置其中第一页为非访问区。该8M空间的功能分配如下 图：</p><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><img alt="图4 栈结构示意" src="http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/4.gif" height="246" border="0" width="527" style="word-wrap: break-word; border: 0px; max-width: 650px; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " />&nbsp;<br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">低地址被保护的页面用来监测栈溢出。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">对于用户指定的栈，在按照指针对界后，设置线程栈顶，并计算出栈底，不做保护，正确性由用户自己保证。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">不论哪种组织方式，线程描述结构总是位于栈顶紧邻堆栈的位置。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N10124" style="word-wrap: break-word; color: #63401b; ">4.线程id和进程id</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">每个LinuxThreads线程都同时具有线程id和进程id，其中进程id就是内核所维护的进程号，而线程id则由LinuxThreads分配和维护。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">__pthread_initial_thread的线程id为 PTHREAD_THREADS_MAX，__pthread_manager_thread的是2*PTHREAD_THREADS_MAX+1，第一 个用户线程的线程id为PTHREAD_THREADS_MAX+2，此后第n个用户线程的线程id遵循以下公式：</p><table border="0" cellpadding="0" cellspacing="0" width="100%" style="word-wrap: break-word; color: #000000; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; text-align: start; background-color: #f5f7f8; "><tbody style="word-wrap: break-word; "><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">tid=n*PTHREAD_THREADS_MAX+n+1</td></tr></tbody></table><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">这种分配方式保证了进程中所有的线程（包括已经退出）都不会有相同的线程id，而线程id的类型pthread_t定义为无符号长整型（unsigned long int），也保证了有理由的运行时间内线程id不会重复。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">从线程id查找线程数据结构是在pthread_handle()函数中完成的，实际上只是将线程号按PTHREAD_THREADS_MAX取模，得到的就是该线程在__pthread_handles中的索引。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N1013A" style="word-wrap: break-word; color: #63401b; ">5.线程的创建</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">在pthread_create()向管理线程发送REQ_CREATE请求之后，管理线程即调用 pthread_handle_create()创建新线程。分配栈、设置thread属性后，以pthread_start_thread()为函数入 口调用__clone()创建并启动新线程。pthread_start_thread()读取自身的进程id号存入线程描述结构中，并根据其中记录的调 度方法配置调度。一切准备就绪后，再调用真正的线程执行函数，并在此函数返回后调用pthread_exit()清理现场。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N10143" style="word-wrap: break-word; color: #63401b; ">6.LinuxThreads的不足</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">由于Linux内核的限制以及实现难度等等原因，LinuxThreads并不是完全POSIX兼容的，在它的发行README中有说明。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">1)进程id问题</strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">这个不足是最关键的不足，引起的原因牵涉到LinuxThreads的"一对一"模型。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">Linux内核并不支持真正意义上的线程，LinuxThreads是用与普通进程具有同样内核调度视图的轻量级进程来实现线程支持 的。这些轻量级进程拥有独立的进程id，在进程调度、信号处理、IO等方面享有与普通进程一样的能力。在源码阅读者看来，就是Linux内核的 clone()没有实现对CLONE_PID参数的支持。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">在内核do_fork()中对CLONE_PID的处理是这样的：</p><table border="0" cellpadding="0" cellspacing="0" width="100%" style="word-wrap: break-word; color: #000000; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; text-align: start; background-color: #f5f7f8; "><tbody style="word-wrap: break-word; "><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">if (clone_flags &amp; CLONE_PID) { if (current-&gt;pid) goto fork_out; }</td></tr></tbody></table><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">这段代码表明，目前的Linux内核仅在pid为0的时候认可CLONE_PID参数，实际上，仅在SMP初始化，手工创建进程的时候才会使用CLONE_PID参数。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">按照POSIX定义，同一进程的所有线程应该共享一个进程id和父进程id，这在目前的"一对一"模型下是无法实现的。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">2)信号处理问题</strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">由于异步信号是内核以进程为单位分发的，而LinuxThreads的每个线程对内核来说都是一个进程，且没有实现"线程组"，因此，某些语义不符合POSIX标准，比如没有实现向进程中所有线程发送信号，README对此作了说明。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">如果核心不提供实时信号，LinuxThreads将使用SIGUSR1和SIGUSR2作为内部使用的restart和cancel 信号，这样应用程序就不能使用这两个原本为用户保留的信号了。在Linux kernel 2.1.60以后的版本都支持扩展的实时信号（从_SIGRTMIN到_SIGRTMAX），因此不存在这个问题。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">某些信号的缺省动作难以在现行体系上实现，比如SIGSTOP和SIGCONT，LinuxThreads只能将一个线程挂起，而无法挂起整个进程。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">3)线程总数问题</strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">LinuxThreads将每个进程的线程最大数目定义为1024，但实际上这个数值还受到整个系统的总进程数限制，这又是由于线程其实是核心进程。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">在kernel 2.4.x中，采用一套全新的总进程数计算方法，使得总进程数基本上仅受限于物理内存的大小，计算公式在kernel/fork.c的fork_init()函数中：</p><table border="0" cellpadding="0" cellspacing="0" width="100%" style="word-wrap: break-word; color: #000000; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; text-align: start; background-color: #f5f7f8; "><tbody style="word-wrap: break-word; "><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 8</td></tr></tbody></table><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">在i386上，THREAD_SIZE=2*PAGE_SIZE，PAGE_SIZE=2^12（4KB），mempages=物理内 存大小/PAGE_SIZE，对于256M的内存的机器，mempages=256*2^20/2^12=256*2^8，此时最大线程数为4096。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">但为了保证每个用户（除了root）的进程总数不至于占用一半以上物理内存，fork_init()中继续指定：</p><table border="0" cellpadding="0" cellspacing="0" width="100%" style="word-wrap: break-word; color: #000000; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; text-align: start; background-color: #f5f7f8; "><tbody style="word-wrap: break-word; "><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2; init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2;</td></tr></tbody></table><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">这些进程数目的检查都在do_fork()中进行，因此，对于LinuxThreads来说，线程总数同时受这三个因素的限制。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">4)管理线程问题</strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">管理线程容易成为瓶颈，这是这种结构的通病；同时，管理线程又负责用户线程的清理工作，因此，尽管管理线程已经屏蔽了大部分的信号，但一旦管理线程死亡，用户线程就不得不手工清理了，而且用户线程并不知道管理线程的状态，之后的线程创建等请求将无人处理。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">5)同步问题</strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">LinuxThreads中的线程同步很大程度上是建立在信号基础上的，这种通过内核复杂的信号处理机制的同步方式，效率一直是个问题。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">6）其他POSIX兼容性问题</strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">Linux中很多系统调用，按照语义都是与进程相关的，比如nice、setuid、setrlimit等，在目前的LinuxThreads中，这些调用都仅仅影响调用者线程。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">7）实时性问题</strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">线程的引入有一定的实时性考虑，但LinuxThreads暂时不支持，比如调度选项，目前还没有实现。不仅LinuxThreads如此，标准的Linux在实时性上考虑都很少。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N101B5" style="word-wrap: break-word; color: #63401b; ">四.其他的线程实现机制</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">LinuxThreads的问题，特别是兼容性上的问题，严重阻碍了Linux上的跨平台应用（如Apache）采用多线程设计，从而 使得Linux上的线程应用一直保持在比较低的水平。在Linux社区中，已经有很多人在为改进线程性能而努力，其中既包括用户级线程库，也包括核心级和 用户级配合改进的线程库。目前最为人看好的有两个项目，一个是RedHat公司牵头研发的NPTL（Native Posix Thread Library），另一个则是IBM投资开发的NGPT（Next Generation Posix Threading），二者都是围绕完全兼容POSIX 1003.1c，同时在核内和核外做工作以而实现多对多线程模型。这两种模型都在一定程度上弥补了LinuxThreads的缺点，且都是重起炉灶全新设 计的。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">1.NPTL</strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">NPTL的设计目标归纳可归纳为以下几点：</p><ul style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style-position: outside; list-style-image: none; line-height: 24px; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8; "><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">POSIX兼容性</li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">SMP结构的利用</li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">低启动开销</li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">低链接开销（即不使用线程的程序不应当受线程库的影响）</li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">与LinuxThreads应用的二进制兼容性</li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">软硬件的可扩展能力</li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">多体系结构支持</li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">NUMA支持</li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">与C++集成</li></ul><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">在技术实现上，NPTL仍然采用1:1的线程模型，并配合glibc和最新的Linux Kernel2.5.x开发版在信号处理、线程同步、存储管理等多方面进行了优化。和LinuxThreads不同，NPTL没有使用管理线程，核心线程 的管理直接放在核内进行，这也带了性能的优化。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">主要是因为核心的问题，NPTL仍然不是100%POSIX兼容的，但就性能而言相对LinuxThreads已经有很大程度上的改进了。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">2.NGPT</strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">IBM的开放源码项目NGPT在2003年1月10日推出了稳定的2.2.0版，但相关的文档工作还差很多。就目前所知，NGPT是基于GNU Pth（GNU Portable Threads）项目而实现的M:N模型，而GNU Pth是一个经典的用户级线程库实现。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">按照2003年3月NGPT官方网站上的通知，NGPT考虑到NPTL日益广泛地为人所接受，为避免不同的线程库版本引起的混乱，今后将不再进行进一步开发，而今进行支持性的维护工作。也就是说，NGPT已经放弃与NPTL竞争下一代Linux POSIX线程库标准。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">3.其他高效线程机制</strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">此处不能不提到Scheduler Activations。这个1991年在ACM上发表的多线程内核结构影响了很多多线程内核的设计，其中包括Mach3.0、NetBSD和商业版本 Digital Unix（现在叫Compaq True64 Unix）。它的实质是在使用用户级线程调度的同时，尽可能地减少用户级对核心的系统调用请求，而后者往往是运行开销的重要来源。采用这种结构的线程机 制，实际上是结合了用户级线程的灵活高效和核心级线程的实用性，因此，包括Linux、FreeBSD在内的多个开放源码操作系统设计社区都在进行相关研 究，力图在本系统中实现Scheduler Activations。<br /><br />转自：<a href="http://blog.chinaunix.net/uid-20556054-id-3075951.html">http://blog.chinaunix.net/uid-20556054-id-3075951.html</a></p><img src ="http://www.cppblog.com/mysileng/aggbug/196408.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-18 13:57 <a href="http://www.cppblog.com/mysileng/archive/2012/12/18/196408.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多进程与多线程（七）--多线程效率(转)</title><link>http://www.cppblog.com/mysileng/archive/2012/12/18/196407.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 18 Dec 2012 05:56:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/18/196407.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196407.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/18/196407.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196407.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196407.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 实验环境：CPU: 双核 Intel(R) Xeon(R) CPU 5130&nbsp; @ 2.00GHz，内存：1G系统：Red Hat Enterprise Linux ES release 4 (Nahant Update 4)内核：2.6.9-42.ELsmp实验程序：singlethread.c#include&nbsp;&lt;stdio.h&gt;#include&nbsp;&lt...&nbsp;&nbsp;<a href='http://www.cppblog.com/mysileng/archive/2012/12/18/196407.html'>阅读全文</a><img src ="http://www.cppblog.com/mysileng/aggbug/196407.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-18 13:56 <a href="http://www.cppblog.com/mysileng/archive/2012/12/18/196407.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多进程与多线程（六）--LinuxThreads(转)</title><link>http://www.cppblog.com/mysileng/archive/2012/12/18/196406.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 18 Dec 2012 05:55:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/18/196406.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196406.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/18/196406.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196406.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196406.html</trackback:ping><description><![CDATA[<p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">（注：这篇文章转自网络，虽然Linux从内核2.6开始，多线程已使用NPTL技术，但是这篇文章对我们理解多线程技术还是挺有用的）<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">Linux内核对多进程和多线程的支持方式：</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 线程机制支持并发程序设计技术，在多处理器上能真正保证并行处理。而在linux实现线程很特别，linux把所有的线程都当作进程实现。linux下线 程看起来就像普通进程(只是该进程和其他进程共享资源，如地址空间)。上述机制与Microsoft windows或是Sun Solaris实现差异很大。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Linux的线程实现是在核外进行的，核内提供的是创建进程的接口do_fork()。内核提供了两个系统调用__clone()和fork()，最终都 用不同的参数调用do_fork()核内API。 do_fork() 提供了很多参数，包括CLONE_VM（共享内存空间）、CLONE_FS（共享文件系统信息）、CLONE_FILES（共享文件描述符表）、 CLONE_SIGHAND（共享信号句柄表）和CLONE_PID（共享进程ID，仅对核内进程，即0号进程有效）。当使用fork系统调用产生多进程 时，内核调用do_fork()不使用任何共享属性，进程拥有独立的运行环境。当使用pthread_create()来创建线程时，则最终设置了所有这 些属性来调用__clone()，而这些参数又全部传给核内的do_fork()，从而创建的&#8221;进程&#8221;拥有共享的运行环境，只有栈是独立的，由 __clone()传入。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;即：Linux下<strong style="word-wrap: break-word; ">不管是多线程编程还是多进程编程，最终都是用</strong><strong style="word-wrap: break-word; ">do_fork</strong><strong style="word-wrap: break-word; ">实现</strong>的 多进程编程，只是进程创建时的参数不同，从而导致有不同的共享环境。Linux线程在核内是以轻量级进程的形式存在的，拥有独立的进程表项，而所有的创 建、同步、删除等操作都在核外pthread库中进行。pthread 库使用一个管理线程（__pthread_manager() ，每个进程独立且唯一）来管理线程的创建和终止，为线程分配线程ID，发送线程相关的信号，而主线程pthread_create()） 的调用者则通过管道将请求信息传给管理线程。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">很多朋友都说使用多线程的好处是资源占用少，其隐含之意就是说进程占用资源比线程多，对吧？但实际上Linux下多进程是否就真的点用很多资源呢？ 暂且不说进程是否比线程占用资源多，就进程占用资源的多少情况而言，Linux确实是做得相当节省的。产生一个多进程时肯定是要产生的一点内存是要复制进 程表项，即一个task_struct结构，但这个结构本身做得相当小巧。其它对于一个进程来说必须有的数据段、代码段、堆栈段是不是全盘复制呢？对于多 进程来说，代码段是肯定不用复制的，因为父进程和各子进程的代码段是相同的，数据段和堆栈段呢？也不一定，因为在Linux里广泛使用的一个技术叫 copy-on-write，即写时拷贝。copy-on-write意味着什么呢？意味着资源节省，假设有一个变量x在父进程里存在，当这个父进程创建 一个子进程或多个子进程时这个变量x是否复制到了子进程的内存空间呢？不会的，子进程和父进程使用同一个内存空间的变量，但当子进程或父进程要改变变量x 的值时就会复制该变量，从而导致父子进程里的变量值不同。<strong style="word-wrap: break-word; ">父子进程变量是互不影响的，由于父子进程地址空间是完全隔开的，变量的地址可以是完全相同的</strong>。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Linux的&#8221;线程&#8221;和&#8221;进程&#8221;实际上处于一个调度层次，共享一个进程标识符空间，这种限制使得不可能在Linux上实现完全意义上的POSIX线程机 制，因此众多的Linux线程库实现尝试都只能尽可能实现POSIX的绝大部分语义，并在功能上尽可能逼近。Linux进程的创建是非常迅速的。内核设计 与实现一书中甚至指出Linux创建进程的速度和其他针对线程优化的操作系统（Windows,Solaris）创建线程的速度相比，测试结果非常的好， 也就是说创建速度很快。由于异步信号是内核以进程为单位分发的，而LinuxThreads的每个线程对内核来说都是一个进程，且没有实现&#8221;线程组&#8221;，因 此，某些语义不符合POSIX标准，比如没有实现向进程中所有线程发送信号，README对此作了说明。LinuxThreads中的线程同步很大程度上 是建立在信号基础上的，这种通过内核复杂的信号处理机制的同步方式，效率一直是个问题。LinuxThreads 的问题，特别是兼容性上的问题，严重阻碍了Linux上的跨平台应用（如Apache）采用多线程设计，从而使得Linux上的线程应用一直保持在比较低 的水平。在Linux社区中，已经有很多人在为改进线程性能而努力，其中既包括用户级线程库，也包括核心级和用户级配合改进的线程库。目前最为人看好的有 两个项目，一个是RedHat公司牵头研发的NPTL（Native Posix Thread Library），另一个则是IBM投资开发的NGPT（Next Generation Posix Threading），二者都是围绕完全兼容POSIX 1003.1c，同时在核内和核外做工作以而实现多对多线程模型。这两种模型都在一定程度上弥补了LinuxThreads的缺点，且都是重起炉灶全新设 计的。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 综上所述的<strong style="word-wrap: break-word; ">结论是在</strong><strong style="word-wrap: break-word; ">Linux</strong><strong style="word-wrap: break-word; ">下编程多用多进程编程少用多线程编程</strong>。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IBM有个家伙做了个测试，发现切换线程context的时候，windows比linux快一倍多。进出最快的锁（windows2k的 critical section和linux的pthread_mutex），windows比linux的要快五倍左右。当然这并不是说linux不好，而且在经过实际 编程之后，综合来看我觉得linux更适合做high performance server，不过在多线程这个具体的领域内，linux还是稍逊windows一点。这应该是情有可原的，毕竟unix家族都是从多进程过来的，而 windows从头就是多线程的。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">如果是UNIX/linux环境，采用多线程没必要。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">多线程比多进程性能高？误导！</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">应该说，<strong style="word-wrap: break-word; ">多线程比多进程成本低，但性能更低</strong>。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">在UNIX环境，多进程调度开销比多线程调度开销，没有显著区别，就是说，UNIX进程调度效率是很高的。内存消耗方面，二者只差全局数据区，现在内存都很便宜，服务器内存动辄若干G，根本不是问题。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">多进程是立体交通系统，虽然造价高，上坡下坡多耗点油，但是不堵车。</strong><strong style="word-wrap: break-word; "></strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">多线程是平面交通系统，造价低，但红绿灯太多，老堵车。</strong><strong style="word-wrap: break-word; "></strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">我们现在都开跑车，油（主频）有的是，不怕上坡下坡，就怕堵车。</p><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">高性能交易服务器中间件，如TUXEDO，都是主张多进程的。实际测试表明，TUXEDO性能和并发效率是非常高的。TUXEDO是贝尔实验室的，与UNIX同宗，应该是对UNIX理解最为深刻的，他们的意见应该具有很大的参考意义</span><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">注：</span><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8; "><div id="commentbody-64" style="word-wrap: break-word; margin: 0px; line-height: 1.5; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; ">关于那个critical section和pthread_mutex_t，critical section本质上是一个自旋锁，短期锁当然快，要比也该是和pthread_spinlock_t比。</p></div></div><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">mutex和critical section的确是不能比的。一个涉及到内核，一个没有涉及到内核。</p><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">转自http://www.soft-bin.com/html/2010/07/09/%E5%A4%9A%E8%BF%9B%E7%A8%8Bvs%E5%A4%9A%E7%BA%BF%E7%A8%8B%EF%BC%8C%E4%B8%80%E4%B8%AA%E9%95%BF%E6%9C%9F%E7%9A%84%E4%BA%89%E8%AE%BA.html，貌似他也是转别人的。</span>&nbsp;<br /><br />转自:<a href="http://blog.chinaunix.net/uid-20556054-id-3068371.html">http://blog.chinaunix.net/uid-20556054-id-3068371.html</a><img src ="http://www.cppblog.com/mysileng/aggbug/196406.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-18 13:55 <a href="http://www.cppblog.com/mysileng/archive/2012/12/18/196406.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多进程与多线程（五）--Linux 线程模型的比较：LinuxThreads 和 NPTL(转)</title><link>http://www.cppblog.com/mysileng/archive/2012/12/18/196405.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 18 Dec 2012 05:52:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/18/196405.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196405.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/18/196405.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196405.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196405.html</trackback:ping><description><![CDATA[<p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">当 Linux 最初开发时，在内核中并不能真正支持线程。但是它的确可以通过 clone() 系统调用将进程作为可调度的实体。这个调用创建了调用进程（calling process）的一个拷贝，这个拷贝与调用进程共享相同的地址空间。LinuxThreads 项目使用这个调用来完全在用户空间模拟对线程的支持。不幸的是，这种方法有一些缺点，尤其是在信号处理、调度和进程间同步原语方面都存在问题。另外，这个 线程模型也不符合 POSIX 的要求。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">要改进 LinuxThreads，非常明显我们需要内核的支持，并且需要重写线程库。有两个相互竞争的项目开始来满足这些要求。一个包括 IBM 的开发人员的团队开展了 NGPT（Next-Generation POSIX Threads）项目。同时，Red Hat 的一些开发人员开展了 NPTL 项目。NGPT 在 2003 年中期被放弃了，把这个领域完全留给了 NPTL。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">尽管从 LinuxThreads 到 NPTL 看起来似乎是一个必然的过程，但是如果您正在为一个历史悠久的 Linux 发行版维护一些应用程序，并且计划很快就要进行升级，那么如何迁移到 NPTL 上就会变成整个移植过程中重要的一个部分。另外，我们可能会希望了解二者之间的区别，这样就可以对自己的应用程序进行设计，使其能够更好地利用这两种技 术。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">本文详细介绍了这些线程模型分别是在哪些发行版上实现的。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N1004F" style="word-wrap: break-word; color: #63401b; ">LinuxThreads 设计细节</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><em style="word-wrap: break-word; ">线程</em>&nbsp;将应用程序划分成一个或多个同时运行的任务。线程与传统的多任务<em style="word-wrap: break-word; ">进程</em>&nbsp;之间的区别在于：线程共享的是单个进程的状态信息，并会直接共享内存和其他资源。同一个进程中线程之间的上下文切换通常要比进程之间的上下文切换速度更 快。因此，多线程程序的优点就是它可以比多进程应用程序的执行速度更快。另外，使用线程我们可以实现并行处理。这些相对于基于进程的方法所具有的优点推动 了 LinuxThreads 的实现。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">LinuxThreads 最初的设计相信相关进程之间的上下文切换速度很快，因此每个内核线程足以处理很多相关的用户级线程。这就导致了<em style="word-wrap: break-word; ">一对一</em>&nbsp;线程模型的革命。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">让我们来回顾一下 LinuxThreads 设计细节的一些基本理念：</p><ul style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style-position: outside; list-style-image: none; line-height: 24px; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8; "><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; ">LinuxThreads 非常出名的一个特性就是<em style="word-wrap: break-word; ">管理线程（manager thread）</em>。管理线程可以满足以下要求：</p><ul style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; "><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">系统必须能够响应终止信号并杀死整个进程。</li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">以堆栈形式使用的内存回收必须在线程完成之后进行。因此，线程无法自行完成这个过程。</li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">终止线程必须进行等待，这样它们才不会进入僵尸状态。</li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">线程本地数据的回收需要对所有线程进行遍历；这必须由管理线程来进行。</li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">如果主线程需要调用 pthread_exit()，那么这个线程就无法结束。主线程要进入睡眠状态，而管理线程的工作就是在所有线程都被杀死之后来唤醒这个主线程。</li></ul><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">为了维护线程本地数据和内存，LinuxThreads 使用了进程地址空间的高位内存（就在堆栈地址之下）。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">原语的同步是使用<em style="word-wrap: break-word; ">信号</em>&nbsp;来实现的。例如，线程会一直阻塞，直到被信号唤醒为止。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">在克隆系统的最初设计之下，LinuxThreads 将每个线程都是作为一个具有惟一进程 ID 的进程实现的。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">终止信号可以杀死所有的线程。LinuxThreads 接收到终止信号之后，管理线程就会使用相同的信号杀死所有其他线程（进程）。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">根据 LinuxThreads 的设计，如果一个异步信号被发送了，那么管理线程就会将这个信号发送给一个线程。如果这个线程现在阻塞了这个信号，那么这个信号也就会被挂起。这是因为管理线程无法将这个信号发送给进程；相反，每个线程都是作为一个进程在执行。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">线程之间的调度是由内核调度器来处理的。</li></ul><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N100A7" style="word-wrap: break-word; color: #63401b; ">LinuxThreads 及其局限性</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">LinuxThreads 的设计通常都可以很好地工作；但是在压力很大的应用程序中，它的性能、可伸缩性和可用性都会存在问题。下面让我们来看一下 LinuxThreads 设计的一些局限性：</p><ul style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style-position: outside; list-style-image: none; line-height: 24px; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8; "><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">它使用管理线程来创建线程，并对每个进程所拥有的所有线程进行协调。这增加了创建和销毁线程所需要的开销。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">由于它是围绕一个管理线程来设计的，因此会导致很多的上下文切换的开销，这可能会妨碍系统的可伸缩性和性能。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">由于管理线程只能在一个 CPU 上运行，因此所执行的同步操作在 SMP 或 NUMA 系统上可能会产生可伸缩性的问题。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">由于线程的管理方式，以及每个线程都使用了一个不同的进程 ID，因此 LinuxThreads 与其他与 POSIX 相关的线程库并不兼容。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">信号用来实现同步原语，这会影响操作的响应时间。另外，将信号发送到主进程的概念也并不存在。因此，这并不遵守 POSIX 中处理信号的方法。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">LinuxThreads 中对信号的处理是按照每线程的原则建立的，而不是按照每进程的原则建立的，这是因为每个线程都有一个独立的进程 ID。由于信号被发送给了一个专用的线程，因此信号是<em style="word-wrap: break-word; ">串行化的</em>&nbsp;&#8212;&#8212; 也就是说，信号是透过这个线程再传递给其他线程的。这与 POSIX 标准对线程进行并行处理的要求形成了鲜明的对比。例如，在 LinuxThreads 中，通过 kill() 所发送的信号被传递到一些单独的线程，而不是集中整体进行处理。这意味着如果有线程阻塞了这个信号，那么 LinuxThreads 就只能对这个线程进行排队，并在线程开放这个信号时在执行处理，而不是像其他没有阻塞信号的线程中一样立即处理这个信号。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">由于 LinuxThreads 中的每个线程都是一个进程，因此用户和组 ID 的信息可能对单个进程中的所有线程来说都不是通用的。例如，一个多线程的 setuid()/setgid() 进程对于不同的线程来说可能都是不同的。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">有一些情况下，所创建的多线程核心转储中并没有包含所有的线程信息。同样，这种行为也是每个线程都是一个进程这个事实所导致的结果。如果任何线程 发生了问题，我们在系统的核心文件中只能看到这个线程的信息。不过，这种行为主要适用于早期版本的 LinuxThreads 实现。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">由于每个线程都是一个单独的进程，因此 /proc 目录中会充满众多的进程项，而这实际上应该是线程。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">由于每个线程都是一个进程，因此对每个应用程序只能创建有限数目的线程。例如，在 IA32 系统上，可用进程总数 &#8212;&#8212; 也就是可以创建的线程总数 &#8212;&#8212; 是 4,090。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">由于计算线程本地数据的方法是基于堆栈地址的位置的，因此对于这些数据的访问速度都很慢。另外一个缺点是用户无法可信地指定堆栈的大小，因为用户可能会意外地将堆栈地址映射到本来要为其他目的所使用的区域上了。<em style="word-wrap: break-word; ">按需增长（grow on demand）</em>&nbsp;的概念（也称为<em style="word-wrap: break-word; ">浮动堆栈</em>&nbsp;的概念）是在 2.4.10 版本的 Linux 内核中实现的。在此之前，LinuxThreads 使用的是固定堆栈。</li></ul><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N100FD" style="word-wrap: break-word; color: #63401b; ">关于 NPTL</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">NPTL，或称为 Native POSIX Thread Library，是 Linux 线程的一个新实现，它克服了 LinuxThreads 的缺点，同时也符合 POSIX 的需求。与 LinuxThreads 相比，它在性能和稳定性方面都提供了重大的改进。与 LinuxThreads 一样，NPTL 也实现了一对一的模型。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">Ulrich Drepper 和 Ingo Molnar 是 Red Hat 参与 NPTL 设计的两名员工。他们的总体设计目标如下：</p><ul style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style-position: outside; list-style-image: none; line-height: 24px; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8; "><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">这个新线程库应该兼容 POSIX 标准。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">这个线程实现应该在具有很多处理器的系统上也能很好地工作。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">为一小段任务创建新线程应该具有很低的启动成本。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">NPTL 线程库应该与 LinuxThreads 是二进制兼容的。注意，为此我们可以使用 LD_ASSUME_KERNEL，这会在本文稍后进行讨论。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">这个新线程库应该可以利用 NUMA 支持的优点。</li></ul><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N10127" style="word-wrap: break-word; color: #63401b; ">NPTL 的优点</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">与 LinuxThreads 相比，NPTL 具有很多优点：</p><ul style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style-position: outside; list-style-image: none; line-height: 24px; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8; "><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">NPTL 没有使用管理线程。管理线程的一些需求，例如向作为进程一部分的所有线程发送终止信号，是并不需要的；因为内核本身就可以实现这些功能。内核还会处理每个 线程堆栈所使用的内存的回收工作。它甚至还通过在清除父线程之前进行等待，从而实现对所有线程结束的管理，这样可以避免僵尸进程的问题。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">由于 NPTL 没有使用管理线程，因此其线程模型在 NUMA 和 SMP 系统上具有更好的可伸缩性和同步机制。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">使用 NPTL 线程库与新内核实现，就可以避免使用信号来对线程进行同步了。为了这个目的，NPTL 引入了一种名为<em style="word-wrap: break-word; ">futex</em>&nbsp;的新机制。futex 在共享内存区域上进行工作，因此可以在进程之间进行共享，这样就可以提供进程间 POSIX 同步机制。我们也可以在进程之间共享一个 futex。这种行为使得进程间同步成为可能。实际上，NPTL 包含了一个 PTHREAD_PROCESS_SHARED 宏，使得开发人员可以让用户级进程在不同进程的线程之间共享互斥锁。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">由于 NPTL 是 POSIX 兼容的，因此它对信号的处理是按照每进程的原则进行的；getpid() 会为所有的线程返回相同的进程 ID。例如，如果发送了 SIGSTOP 信号，那么整个进程都会停止；使用 LinuxThreads，只有接收到这个信号的线程才会停止。这样可以在基于 NPTL 的应用程序上更好地利用调试器，例如 GDB。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">由于在 NPTL 中所有线程都具有一个父进程，因此对父进程汇报的资源使用情况（例如 CPU 和内存百分比）都是对整个进程进行统计的，而不是对一个线程进行统计的。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">NPTL 线程库所引入的一个实现特性是对 ABI（应用程序二进制接口）的支持。这帮助实现了与 LinuxThreads 的向后兼容性。这个特性是通过使用 LD_ASSUME_KERNEL 实现的，下面就来介绍这个特性。</li></ul><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N10162" style="word-wrap: break-word; color: #63401b; ">LD_ASSUME_KERNEL 环境变量</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">正如上面介绍的一样，ABI 的引入使得可以同时支持 NPTL 和 LinuxThreads 模型。基本上来说，这是通过 ld （一个动态链接器/加载器）来进行处理的，它会决定动态链接到哪个运行时线程库上。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">举例来说，下面是 WebSphere&#174; Application Server 对这个变量所使用的一些通用设置；您可以根据自己的需要进行适当的设置：</p><ul style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style-position: outside; list-style-image: none; line-height: 24px; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8; "><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">LD_ASSUME_KERNEL=2.4.19：这会覆盖 NPTL 的实现。这种实现通常都表示使用标准的 LinuxThreads 模型，并启用浮动堆栈的特性。</li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">LD_ASSUME_KERNEL=2.2.5：这会覆盖 NPTL 的实现。这种实现通常都表示使用 LinuxThreads 模型，同时使用固定堆栈大小。</li></ul><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">我们可以使用下面的命令来设置这个变量：</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">export LD_ASSUME_KERNEL=2.4.19</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">注意，对于任何 LD_ASSUME_KERNEL 设置的支持都取决于目前所支持的线程库的 ABI 版本。例如，如果线程库并不支持 2.2.5 版本的 ABI，那么用户就不能将 LD_ASSUME_KERNEL 设置为 2.2.5。通常，NPTL 需要 2.4.20，而 LinuxThreads 则需要 2.4.1。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">如果您正运行的是一个启用了 NPTL 的 Linux 发行版，但是应用程序却是基于 LinuxThreads 模型来设计的，那么所有这些设置通常都可以使用。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N10195" style="word-wrap: break-word; color: #63401b; ">GNU_LIBPTHREAD_VERSION 宏</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">大部分现代 Linux 发行版都预装了 LinuxThreads 和 NPTL，因此它们提供了一种机制来在二者之间进行切换。要查看您的系统上正在使用的是哪个线程库，请运行下面的命令：</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">$ getconf GNU_LIBPTHREAD_VERSION</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">这会产生类似于下面的输出结果：</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">NPTL 0.34</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">或者：</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">linuxthreads-0.10</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N101B3" style="word-wrap: break-word; color: #63401b; ">Linux 发行版所使用的线程模型、glibc 版本和内核版本</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">表 1 列出了一些流行的 Linux 发行版，以及它们所采用的线程实现的类型、glibc 库和内核版本。</p><table summary="Linux distributions and their threading implementations" border="0" cellpadding="0" cellspacing="0" width="100%" style="word-wrap: break-word; color: #000000; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; text-align: start; background-color: #f5f7f8; "><caption style="word-wrap: break-word; text-align: left; font-size: 14px; font-weight: bold; "><em style="word-wrap: break-word; ">表 1. Linux 发行版及其线程实现</em></caption><tbody style="word-wrap: break-word; "><tr style="word-wrap: break-word; "><th style="word-wrap: break-word; ">线程实现</th><th style="word-wrap: break-word; ">C 库</th><th style="word-wrap: break-word; ">发行版</th><th style="word-wrap: break-word; ">内核</th></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">LinuxThreads 0.7, 0.71 (for libc5)</td><td style="word-wrap: break-word; line-height: 1.5; ">libc 5.x</td><td style="word-wrap: break-word; line-height: 1.5; ">Red Hat 4.2</td><td style="word-wrap: break-word; line-height: 1.5; "><br style="word-wrap: break-word; " /></td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">LinuxThreads 0.7, 0.71 (for glibc 2)</td><td style="word-wrap: break-word; line-height: 1.5; ">glibc 2.0.x</td><td style="word-wrap: break-word; line-height: 1.5; ">Red Hat 5.x</td><td style="word-wrap: break-word; line-height: 1.5; "><br style="word-wrap: break-word; " /></td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">LinuxThreads 0.8</td><td style="word-wrap: break-word; line-height: 1.5; ">glibc 2.1.1</td><td style="word-wrap: break-word; line-height: 1.5; ">Red Hat 6.0</td><td style="word-wrap: break-word; line-height: 1.5; "><br style="word-wrap: break-word; " /></td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">LinuxThreads 0.8</td><td style="word-wrap: break-word; line-height: 1.5; ">glibc 2.1.2</td><td style="word-wrap: break-word; line-height: 1.5; ">Red Hat 6.1 and 6.2</td><td style="word-wrap: break-word; line-height: 1.5; "><br style="word-wrap: break-word; " /></td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">LinuxThreads 0.9</td><td style="word-wrap: break-word; line-height: 1.5; "><br style="word-wrap: break-word; " /></td><td style="word-wrap: break-word; line-height: 1.5; ">Red Hat 7.2</td><td style="word-wrap: break-word; line-height: 1.5; ">2.4.7</td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">LinuxThreads 0.9</td><td style="word-wrap: break-word; line-height: 1.5; ">glibc 2.2.4</td><td style="word-wrap: break-word; line-height: 1.5; ">Red Hat 2.1 AS</td><td style="word-wrap: break-word; line-height: 1.5; ">2.4.9</td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">LinuxThreads 0.10</td><td style="word-wrap: break-word; line-height: 1.5; ">glibc 2.2.93</td><td style="word-wrap: break-word; line-height: 1.5; ">Red Hat 8.0</td><td style="word-wrap: break-word; line-height: 1.5; ">2.4.18</td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">NPTL 0.6</td><td style="word-wrap: break-word; line-height: 1.5; ">glibc 2.3</td><td style="word-wrap: break-word; line-height: 1.5; ">Red Hat 9.0</td><td style="word-wrap: break-word; line-height: 1.5; ">2.4.20</td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">NPTL 0.61</td><td style="word-wrap: break-word; line-height: 1.5; ">glibc 2.3.2</td><td style="word-wrap: break-word; line-height: 1.5; ">Red Hat 3.0 EL</td><td style="word-wrap: break-word; line-height: 1.5; ">2.4.21</td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">NPTL 2.3.4</td><td style="word-wrap: break-word; line-height: 1.5; ">glibc 2.3.4</td><td style="word-wrap: break-word; line-height: 1.5; ">Red Hat 4.0</td><td style="word-wrap: break-word; line-height: 1.5; ">2.6.9</td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">LinuxThreads 0.9</td><td style="word-wrap: break-word; line-height: 1.5; ">glibc 2.2</td><td style="word-wrap: break-word; line-height: 1.5; ">SUSE Linux Enterprise Server 7.1</td><td style="word-wrap: break-word; line-height: 1.5; ">2.4.18</td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">LinuxThreads 0.9</td><td style="word-wrap: break-word; line-height: 1.5; ">glibc 2.2.5</td><td style="word-wrap: break-word; line-height: 1.5; ">SUSE Linux Enterprise Server 8</td><td style="word-wrap: break-word; line-height: 1.5; ">2.4.21</td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">LinuxThreads 0.9</td><td style="word-wrap: break-word; line-height: 1.5; ">glibc 2.2.5</td><td style="word-wrap: break-word; line-height: 1.5; ">United Linux</td><td style="word-wrap: break-word; line-height: 1.5; ">2.4.21</td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; ">NPTL 2.3.5</td><td style="word-wrap: break-word; line-height: 1.5; ">glibc 2.3.3</td><td style="word-wrap: break-word; line-height: 1.5; ">SUSE Linux Enterprise Server 9</td><td style="word-wrap: break-word; line-height: 1.5; ">2.6.5</td></tr></tbody></table><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">注意，从 2.6.x 版本的内核和 glibc 2.3.3 开始，NPTL 所采用的版本号命名约定发生了变化：这个库现在是根据所使用的 glibc 的版本进行编号的。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">Java&#8482; 虚拟机（JVM）的支持可能会稍有不同。IBM 的 JVM 可以支持表 1 中 glibc 版本高于 2.1 的大部分发行版。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="N102BE" style="word-wrap: break-word; color: #63401b; ">结束语</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">LinuxThreads 的限制已经在 NPTL 以及 LinuxThreads 后期的一些版本中得到了克服。例如，最新的 LinuxThreads 实现使用了线程注册来定位线程本地数据；例如在 Intel&#174; 处理器上，它就使用了 %fs 和 %gs 段寄存器来定位访问线程本地数据所使用的虚拟地址。尽管这个结果展示了 LinuxThreads 所采纳的一些修改的改进结果，但是它在更高负载和压力测试中，依然存在很多问题，因为它过分地依赖于一个管理线程，使用它来进行信号处理等操作。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">您应该记住，在使用 LinuxThreads 构建库时，需要使用 -D_REENTRANT 编译时标志。这使得库线程是安全的。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">最后，也许是最重要的事情，请记住 LinuxThreads 项目的创建者已经不再积极更新它了，他们认为 NPTL 会取代 LinuxThreads。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">LinuxThreads 的缺点并不意味着 NPTL 就没有错误。作为一个面向 SMP 的设计，NPTL 也有一些缺点。我曾经看到过在最近的 Red Hat 内核上出现过这样的问题：一个简单线程在单处理器的机器上运行良好，但在 SMP 机器上却挂起了。我相信在 Linux 上还有更多工作要做才能使它具有更好的可伸缩性，从而满足高端应用程序的需求。</p><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="resources" style="word-wrap: break-word; color: #63401b; ">参考资料</a></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">学习</strong></p><ul style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style-position: outside; list-style-image: none; line-height: 24px; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8; "><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">您可以参阅本文在 developerWorks 全球站点上的 英文原文 。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">Ulrich Drepper 和 Ingo Molnar 编写的 &#8220;The Native POSIX Thread Library for Linux&#8221;（PDF）介绍了设计 NPTL 的原因和目标，其中包括了 LinuxThreads 的缺点和 NPTL 的优点。&nbsp;<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">LinuxThreads FAQ 包含了有关 LinuxThreads 和 NPTL 的常见问题。这对于了解早期的 LinuxThreads 实现的缺点来说是一个很好的资源。&nbsp;<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">Ulrich Drepper 撰写的 &#8220;Explaining LD_ASSUME_KERNEL&#8221; 提供了有关这个环境变量的详细介绍。&nbsp;<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">&#8220;Native POSIX Threading Library (NPTL) support&#8221; 从 WebSphere 的视角介绍了 LinuxThreads 和 NPTL 之间的区别，并解释了 WebSphere Application Server 如何支持这两种不同的线程模型。&nbsp;<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">Diagnosis documentation for IBM ports of the JVM 定义了 Java 应用程序在 Linux 上运行时面临问题时所要搜集的诊断信息。&nbsp;<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">在 developerWorks Linux 专区 中可以找到为 Linux 开发人员准备的更多资源。&nbsp;<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">随时关注 developerWorks 技术事件和网络广播。&nbsp;<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li></ul><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">获得产品和技术</strong></p><ul style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style-position: outside; list-style-image: none; line-height: 24px; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8; "><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">LinuxThreads README 对 LinuxThreads 概要进行了介绍。&nbsp;<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">在您的下一个开发项目中采用 IBM 试用软件，这可以从 developerWorks 上直接下载。&nbsp;<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li></ul><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">讨论</strong></p><ul style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style-position: outside; list-style-image: none; line-height: 24px; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8; "><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; ">通过参与 developerWorks blogs 加入 developerWorks 社区。&nbsp;<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /></li></ul><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><a name="author" style="word-wrap: break-word; color: #63401b; ">关于作者</a></p><div ibm-portrait-module=""  ibm-alternate-two"="" style="word-wrap: break-word; margin: 0px; line-height: 1.5; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8; "><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><a name="author1" style="word-wrap: break-word; color: rgb(99, 64, 27); "></a>Vikram Shukla 具有 6 年使用面向对象语言进行开发和设计的经验，目前是位于印度 Banglore 的 IBM Java Technology Center 的一名资深软件工程师，负责对 IBM JVM on Linux 进行支持。<br /><br />转自:<a href="http://blog.chinaunix.net/uid-20556054-id-3068081.html" style="line-height: 1.5; font-size: 12px; ">http://blog.chinaunix.net/uid-20556054-id-3068081.html</a></p></div></div><img src ="http://www.cppblog.com/mysileng/aggbug/196405.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-18 13:52 <a href="http://www.cppblog.com/mysileng/archive/2012/12/18/196405.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多进程与多线程（四）--NPTL(转)</title><link>http://www.cppblog.com/mysileng/archive/2012/12/18/196404.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 18 Dec 2012 05:50:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/18/196404.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196404.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/18/196404.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196404.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196404.html</trackback:ping><description><![CDATA[<p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">Native POSIX Thread Library</p><div id="bodyContent" style="word-wrap: break-word; margin: 0px; line-height: 1.5; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8; "><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; ">维基百科，自由的百科全书</div><div dir="ltr" style="word-wrap: break-word; margin: 0px; line-height: 1.5; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><strong style="word-wrap: break-word; "><span style="word-wrap: break-word; line-height: 1.5; ">Native POSIX Thread Library</span></strong>（<strong style="word-wrap: break-word; "><span style="word-wrap: break-word; line-height: 1.5; ">NPTL</span></strong>）是一个能够使使用<span style="word-wrap: break-word; line-height: 1.5; ">POSIX Threads</span>编写的程序在Linux内核上更有效地运行的软件。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; ">测试表明，NPTL能够成功地在IA-32平台上在两秒种内生成100,000个线程；相应的没有<span style="word-wrap: break-word; line-height: 1.5; ">NPTL</span>的内核将耗费15分钟左右。</p><span id=".E5.8E.86.E5.8F.B2" style="word-wrap: break-word; line-height: 1.5; ">历史</span><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; ">在<span style="word-wrap: break-word; line-height: 1.5; ">Linux</span>内核2.6出现之前进程是(最小)可调度的对象，当时的<span style="word-wrap: break-word; line-height: 1.5; ">Linux</span>不真正支持线程。但是<span style="word-wrap: break-word; line-height: 1.5; ">Linux</span>内核有一个系统调用指令<span style="word-wrap: break-word; line-height: 1.5; ">clone()</span>，这个指令产生一个呼叫调用的进程的复件，而且这个复件与原进程使用同一地址空间。<span style="word-wrap: break-word; line-height: 1.5; ">LinuxThreads</span>计划使用这个系统调用来提供一个内核级的线程支持。但是这个解决方法与真正的<span style="word-wrap: break-word; line-height: 1.5; ">POSIX</span>标准有一些不相容的地方，尤其是在信号处理、进程调度和进程间同步原语方面。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; ">要提高<span style="word-wrap: break-word; line-height: 1.5; ">LinuxThreads</span>的效应很明显需要提供内核支持以及必须重写线程函式库。为了解决这个问题出现了两个互相竞争的项目：一个<span style="word-wrap: break-word; line-height: 1.5; ">IBM</span>的组的项目叫做<span style="word-wrap: break-word; line-height: 1.5; ">NGPT</span>（<span style="word-wrap: break-word; line-height: 1.5; ">Next Generation POSIX Threads</span>，下一代<span style="word-wrap: break-word; line-height: 1.5; ">POSIX</span>线程），另一个组是由<span style="word-wrap: break-word; line-height: 1.5; ">Red Hat</span>程序员组成的。2003年中<span style="word-wrap: break-word; line-height: 1.5; ">NGPT</span>被放弃，几乎与此同时<span style="word-wrap: break-word; line-height: 1.5; ">NPTL</span>公布了。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">NPTL</span>首次是随<span style="word-wrap: break-word; line-height: 1.5; ">Red Hat Linux 9</span>发表的。此前老式的<span style="word-wrap: break-word; line-height: 1.5; ">Linux POSIX</span>线程偶尔会发生系统无法产生线程的毛病，这个毛病的原因是因为在新线程开始的时候系统没有借机先占。当时的<span style="word-wrap: break-word; line-height: 1.5; ">Windows</span>系统对这个问题的解决比较好。<span style="word-wrap: break-word; line-height: 1.5; ">Red Hat</span>在关于<span style="word-wrap: break-word; line-height: 1.5; ">Red Hat Linux 9</span>上的<span style="word-wrap: break-word; line-height: 1.5; ">Java</span>的网页上发表了一篇文章称<span style="word-wrap: break-word; line-height: 1.5; ">NPTL</span>解决了这个问题。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; ">从第3版开始<span style="word-wrap: break-word; line-height: 1.5; ">NPTL</span>是<span style="word-wrap: break-word; line-height: 1.5; ">Red Hat Enterprise Linux</span>的一部分，从<span style="word-wrap: break-word; line-height: 1.5; ">Linux</span>内核2.6开始它被纳入内核。目前它完全被结合入GNU C 函式库。</p><span id=".E8.AE.BE.E8.AE.A1" style="word-wrap: break-word; line-height: 1.5; ">设计</span><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">NPTL</span>的解决方法与<span style="word-wrap: break-word; line-height: 1.5; ">LinuxThreads</span>类似，内核看到的首要抽象依然是一个进程，新线程是通过<span style="word-wrap: break-word; line-height: 1.5; ">clone()</span>系统调用产生的。但是<span style="word-wrap: break-word; line-height: 1.5; ">NPTL</span>需要特殊的内核支持来解决同步的原始类型之间互相竞争的状况。在这种情况下线程必须能够入眠和再复苏。用来完成这个任务的原始类型叫做<span style="word-wrap: break-word; line-height: 1.5; ">futex</span>。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">NPTL</span>是一个所谓的1&#215;1线程函式库。用户产生的线程与内核能够分配的物件之间的联系是一对一的。这是所有线程程式中最简单的。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; ">转自http://zh.wikipedia.org/wiki/Native_POSIX_Thread_Library#cite_note-1<br /><br />转自：<a href="http://blog.chinaunix.net/uid-20556054-id-3068071.html" style="line-height: 1.5; font-size: 12px; ">http://blog.chinaunix.net/uid-20556054-id-3068071.html</a></p></div></div><img src ="http://www.cppblog.com/mysileng/aggbug/196404.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-18 13:50 <a href="http://www.cppblog.com/mysileng/archive/2012/12/18/196404.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多进程与多线程（三）--多进程 or 多线程(转)</title><link>http://www.cppblog.com/mysileng/archive/2012/12/18/196403.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 18 Dec 2012 05:49:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/18/196403.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196403.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/18/196403.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196403.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196403.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: （转自http://programmerdigest.cn/2010/08/1096.html，其中的实验数据重新做过测试，在语言上也有所修改）在Unix上编程采用多线程还是多进程的争执由来已久，这种争执最常见到在B/S通讯中服务端并发技术 的选型上，比如WEB服务器技术中，Apache是采用多进程的（perfork模式，每客户连接对应一个进程，每进程中只存在唯一一个执行线 程），Java的Web...&nbsp;&nbsp;<a href='http://www.cppblog.com/mysileng/archive/2012/12/18/196403.html'>阅读全文</a><img src ="http://www.cppblog.com/mysileng/aggbug/196403.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-18 13:49 <a href="http://www.cppblog.com/mysileng/archive/2012/12/18/196403.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多进程与多线程（二）--鱼与熊掌(转)</title><link>http://www.cppblog.com/mysileng/archive/2012/12/18/196402.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 18 Dec 2012 05:47:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/18/196402.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196402.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/18/196402.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196402.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196402.html</trackback:ping><description><![CDATA[<p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">关于多进程和多线程，教科书上最经典的一句话是&#8220;进程是资源分配的最小单位，线程是CPU调度的最小单位&#8221;。这句话应付考试基本上够了，但如果在工作中遇到类似的选择问题，那就没有那么简单了，选的不好，会让你深受其害。<br style="word-wrap: break-word; " />经常在网络上看到有XDJM问&#8220;多进程好还是多线程好？&#8221;、"Linux下用多进程还是多线程？"等等期望一劳永逸的问题，只能说：没有最好，只有更好，根据实际情况来判断，哪个更加合适就是哪个好。<br style="word-wrap: break-word; " />我们按照多个不同的维度，来看看多进程和多线程的对比（注：因为是感性的比较，因此都是相对的，不是说一个好得不得了，另一个差的无法忍受）</p><table height="402" border="1" cellpadding="0" cellspacing="0" width="630" style="word-wrap: break-word; color: #000000; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; text-align: start; background-color: #f5f7f8; border-collapse: collapse; border: medium none; "><tbody style="word-wrap: break-word; "><tr style="word-wrap: break-word; "><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border: 1pt solid windowtext; background-color: yellow; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span times="" new=""  roman";="" mso-hansi-font-family:" times=""  roman""="" style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; ">维度</span></p></td><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: solid solid solid none; border-top-color: windowtext; border-right-color: windowtext; border-bottom-color: windowtext; border-top-width: 1pt; border-right-width: 1pt; border-bottom-width: 1pt; background-color: yellow; padding: 0cm 5.4pt; background-position: initial initial; background-repeat: initial initial; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span times="" new=""  roman";="" mso-hansi-font-family:" times=""  roman""="" style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; ">多进程</span></p></td><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: solid solid solid none; border-top-color: windowtext; border-right-color: windowtext; border-bottom-color: windowtext; border-top-width: 1pt; border-right-width: 1pt; border-bottom-width: 1pt; background-color: yellow; padding: 0cm 5.4pt; background-position: initial initial; background-repeat: initial initial; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span times="" new=""  roman";="" mso-hansi-font-family:" times=""  roman""="" style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; ">多线程</span></p></td><td valign="top" width="139" style="word-wrap: break-word; line-height: 1.5; width: 104.5pt; border-style: solid solid solid none; border-top-color: windowtext; border-right-color: windowtext; border-bottom-color: windowtext; border-top-width: 1pt; border-right-width: 1pt; border-bottom-width: 1pt; background-color: yellow; padding: 0cm 5.4pt; background-position: initial initial; background-repeat: initial initial; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span times="" new=""  roman";="" mso-hansi-font-family:" times=""  roman""="" style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; ">总结</span></p></td></tr><tr style="word-wrap: break-word; "><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid; border-right-color: windowtext; border-bottom-color: windowtext; border-left-color: windowtext; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">数据共享、同步</span></p></td><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">数据是分开的:共享复杂，需要用IPC;同步简单</span></p></td><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">多线程共享进程数据：共享简单；同步复杂</span></p></td><td valign="top" width="139" style="word-wrap: break-word; line-height: 1.5; width: 104.5pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">各有优势</span></p></td></tr><tr style="word-wrap: break-word; "><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid; border-right-color: windowtext; border-bottom-color: windowtext; border-left-color: windowtext; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">内存、CPU</span></p></td><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">占用内存多，切换复杂，CPU利用率低</span></p></td><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">占用内存少，切换简单，CPU利用率高</span></p></td><td valign="top" width="139" style="word-wrap: break-word; line-height: 1.5; width: 104.5pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">线程占优</span></p></td></tr><tr style="word-wrap: break-word; "><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid; border-right-color: windowtext; border-bottom-color: windowtext; border-left-color: windowtext; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">创建销毁、切换</span></p></td><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">创建销毁、切换复杂，速度慢&nbsp;<br style="word-wrap: break-word; " /></span></p></td><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">创建销毁、切换简单，速度快&nbsp;<br style="word-wrap: break-word; " /></span></p></td><td valign="top" width="139" style="word-wrap: break-word; line-height: 1.5; width: 104.5pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">线程占优&nbsp;<br style="word-wrap: break-word; " /></span></p></td></tr><tr style="word-wrap: break-word; "><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid; border-right-color: windowtext; border-bottom-color: windowtext; border-left-color: windowtext; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">编程调试<br style="word-wrap: break-word; " /></span></p></td><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">编程简单，调试简单</span></p></td><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">编程复杂，调试复杂</span></p></td><td valign="top" width="139" style="word-wrap: break-word; line-height: 1.5; width: 104.5pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">进程占优&nbsp;<br style="word-wrap: break-word; " /></span></p></td></tr><tr style="word-wrap: break-word; "><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid; border-right-color: windowtext; border-bottom-color: windowtext; border-left-color: windowtext; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">可靠性</span></p></td><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">进程间不会相互影响&nbsp;<br style="word-wrap: break-word; " /></span></p></td><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">一个线程挂掉将导致整个进程挂掉</span></p></td><td valign="top" width="139" style="word-wrap: break-word; line-height: 1.5; width: 104.5pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">进程占优</span></p></td></tr><tr style="word-wrap: break-word; "><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid; border-right-color: windowtext; border-bottom-color: windowtext; border-left-color: windowtext; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">分布式&nbsp;<br style="word-wrap: break-word; " /></span></p></td><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">适应于多核、多机分布 ；如果一台机器不够，扩展到多台机器比较简单<br style="word-wrap: break-word; " /></span></p></td><td valign="top" width="143" style="word-wrap: break-word; line-height: 1.5; width: 107.2pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">适应于多核分布</span></p></td><td valign="top" width="139" style="word-wrap: break-word; line-height: 1.5; width: 104.5pt; border-style: none solid solid none; border-bottom-color: windowtext; border-bottom-width: 1pt; border-right-color: windowtext; border-right-width: 1pt; padding: 0cm 5.4pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; ">进程占优</span></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><br style="word-wrap: break-word; " /></p></td></tr></tbody></table><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">1)需要频繁创建销毁的优先用线程。</span><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">&nbsp;&nbsp; 实例：web服务器。来一个建立一个线程，断了就销毁线程。要是用进程，创建和销毁的代价是很难承受的。</span><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">2）需要进行大量计算的优先使用线程。</span><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">&nbsp;&nbsp; 所谓大量计算，当然就是要消耗很多cpu，切换频繁了，这种情况先线程是最合适的。</span><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">&nbsp;&nbsp; 实例：图像处理、算法处理</span><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">3）强相关的处理用线程，若相关的处理用进程。</span><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">&nbsp;&nbsp; 什么叫强相关、弱相关？理论上很难定义，给个简单的例子就明白了。</span><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">&nbsp;&nbsp; 一般的server需要完成如下任务：消息收发和消息处理。消息收发和消息处理就是弱相关的任务，而消息处理里面可能又分为消息解码、业务处理，这两个任务相对来说相关性就要强多了。因此消息收发和消息处理可以分进程设计，消息解码和业务处理可以分线程设计。</span><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">4）可能扩展到多机分布的用进程，多核分布的用线程。</span><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">5）都满足需求的情况下，用你最熟悉、最拿手的方式。</span><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">&nbsp;&nbsp; 至于&#8221;数据共享、同步&#8220;、&#8220;编程、调试&#8221;、&#8220;可靠性&#8221;这几个维度的所谓的&#8220;复杂、简单&#8221;应该怎么取舍，只能说：没有明确的选择方法。一般有一个选择原则：如果多进程和多线程都能够满足要求，那么选择你最熟悉、最拿手的那个。</span><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">需要提醒的是：虽然有这么多的选择原则，但实际应用中都是&#8220;进程+线程&#8221;的结合方式，千万不要真的陷入一种非此即彼的误区。</span><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><span style="font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; ">转自：http://software.intel.com/zh-cn/blogs/2010/07/20/400004478/</span>&nbsp;<br /><br />转自:<a href="http://blog.chinaunix.net/uid-20556054-id-3061450.html">http://blog.chinaunix.net/uid-20556054-id-3061450.html</a><img src ="http://www.cppblog.com/mysileng/aggbug/196402.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-18 13:47 <a href="http://www.cppblog.com/mysileng/archive/2012/12/18/196402.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多进程与多线程（一）--基本概念(转)</title><link>http://www.cppblog.com/mysileng/archive/2012/12/18/196401.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 18 Dec 2012 05:44:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/18/196401.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196401.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/18/196401.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196401.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196401.html</trackback:ping><description><![CDATA[<p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">进程</strong>（英语：<span style="word-wrap: break-word; line-height: 1.5; ">Process</span>，中国大陆译作<strong style="word-wrap: break-word; ">进程</strong>，台湾译作<strong style="word-wrap: break-word; ">行程</strong>）&nbsp;是具有一定独立功能的程序关于某个数据集合上的一次运行活动，是系统进行资源分配和调度的一个独立单位。<br style="word-wrap: break-word; " />程序是一组指令的有序集合，它本身没有任何运行的含义，只是一个静态实体。进程是程序在某个数据集上的执行，是一个动态实体（进程本身不会运行，是线程的容器。）。它因创建而产生，因调度而运行，因等待资源或事件而被处于等待状态，因完成任务而被撤消，反映了一个程序在一定的数据集上运行的全部动态过程。<br style="word-wrap: break-word; " />若干进程有可能与同一个程序相关系，且每个进程皆可以同步（循序）或不同步（平行）的方式独立运行。进程为现今分时系统的基本运作单位。<br style="word-wrap: break-word; " /><strong style="word-wrap: break-word; "><br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />线程</strong>（英语：<span style="word-wrap: break-word; line-height: 1.5; ">thread</span>，台湾译为<strong style="word-wrap: break-word; ">运行绪），</strong>操作系统技术中的术语，是<span style="word-wrap: break-word; line-height: 1.5; ">操作系统</span>能够进行运算<span style="word-wrap: break-word; line-height: 1.5; ">调度</span>的最小单位。它被包涵在<span style="word-wrap: break-word; line-height: 1.5; ">进程</span>之中，一条线程指的是<span style="word-wrap: break-word; line-height: 1.5; ">进程</span>中一个单一顺序的控制流，一个进程中可以并发多个线程，每条线程并行执行不同的任务。在<span style="word-wrap: break-word; line-height: 1.5; ">Unix System V</span>及SunOS中也被称为轻量进程（lightweight processes），但轻量进程更多指内核线程(kernel thread)，而把用户线程(user thread)称为线程。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">线程是独立调度和分派的基本单位。线程可以操作系统内核调度的内核线程，如Win32 线程；由用户进程自行调度的用户线程，如Linux Portable Thread； 或者由内核与用户进程，如Windows 7的线程，进行混合调度。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">同一进程中的多条线程将共享该进程中的全部系统资源，如虚拟地址空间，文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack)，自己的寄存器环境（register context)，自己的线程本地存储(thread-local storage)。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">一个进程可以有很多线程，每条线程并行执行不同的任务。</p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">在多核或多CPU，或支持Hyper-threading的CPU上使用多线程程序设计的好处是显而易见，即提高了程序的执行吞吐率。在单CPU单核的计算机上，使用多线程技术，也可以把进程中负责IO处理、人机交互而常备阻塞的部分与密集计算的部分分开来执行，编写专门的workhorse线程执行密集计算，从而提高了程序的执行效率。（摘自：http://zh.wikipedia.org/wiki/线程）<strong style="word-wrap: break-word; "><br style="word-wrap: break-word; " /></strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; "><br style="word-wrap: break-word; " /></strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">进程是资源分配的最小单位，线程是CPU调度的最小单位</strong>。线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文.多线程主要是为了节约CPU时间,发挥利用,根据具体情况而定. 线程的运行中需要使用计算机的内存资源和CPU。<br style="word-wrap: break-word; " /></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; "><br style="word-wrap: break-word; " /></strong></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; ">多进程</strong>： 进程是程序在计算机上的一次执行活动。当你运行一个程序，你就启动了一个进程。显然，程序是死的(静态的)，进程是活的(动态的)。进程可以分为系统进程和用户进程。凡是用于完成操作系统的各种功能的进程就是系统进程，它们就是处于运行状态下的操作系统本身；所有由用户启动的进程都是用户进程。进程是操作系统进行资源分配的单位。 进程又被细化为线程，也就是一个进程下有多个能独立运行的更小的单位。在同一个时间里，同一个计算机系统中如果允许两个或两个以上的进程处于运行状态，这便是多任务。现代的操作系统几乎都是多任务操作系统，能够同时管理多个进程的运行。 多任务带来的好处是明显的，比如你可以边听mp3边上网，与此同时甚至可以将下载的文档打印出来，而这些任务之间丝毫不会相互干扰。那么这里就涉及到并行的问题，俗话说，一心不能二用，这对计算机也一样，原则上一个CPU只能分配给一个进程，以便运行这个进程。我们通常使用的计算机中只有一个CPU，也就是说只有一颗心，要让它一心多用，同时运行多个进程，就必须使用并发技术。实现并发技术相当复杂，最容易理解的是&#8220;时间片轮转进程调度算法&#8221;，它的思想简单介绍如下：在操作系统的管理下，所有正在运行的进程轮流使用CPU，每个进程允许占用CPU的时间非常短(比如10毫秒)，这样用户根本感觉不出来 CPU是在轮流为多个进程服务，就好象所有的进程都在不间断地运行一样。但实际上在任何一个时间内有且仅有一个进程占有CPU。 如果一台计算机有多个CPU，情况就不同了，如果进程数小于CPU数，则不同的进程可以分配给不同的CPU来运行，这样，多个进程就是真正同时运行的，这便是并行。但如果进程数大于CPU数，则仍然需要使用并发技术。 进行CPU分配是以线程为单位的，一个进程可能由多个线程组成，这时情况更加复杂，但简单地说，有如下关系：&nbsp;<br style="word-wrap: break-word; " /></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">总线程数&lt;= CPU数量：并行运行&nbsp;<br style="word-wrap: break-word; " /></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">总线程数&gt; CPU数量：并发运行&nbsp;<br style="word-wrap: break-word; " /></p><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; ">并行运行的效率显然高于并发运行，所以在多CPU的计算机中，多任务的效率比较高。但是，如果在多CPU计算机中只运行一个进程(线程)，就不能发挥多CPU的优势。 这里涉及到多任务操作系统的问题，多任务操作系统(如Windows)的基本原理是:操作系统将CPU的时间片分配给多个线程,每个线程在操作系统指定的时间片内完成(注意,这里的多个线程是分属于不同进程的).操作系统不断的从一个线程的执行切换到另一个线程的执行,如此往复,宏观上看来,就好像是多个线程在一起执行.由于这多个线程分属于不同的进程,因此在我们看来,就好像是多个进程在同时执行,这样就实现了多任务.（摘自：http://zhidao.baidu.com/question/2601473）</p><strong style="word-wrap: break-word; "><br style="word-wrap: break-word; " />多线程</strong>：在计算机编程中，一个基本的概念就是同时对多个任务加以控制。许多程序设计问题都要求程序能够停下手头的工作，改为处理其他一些问题，再返回主进程。可以通过多种途径达到这个目的。最开始的时候，那些掌握机器低级语言的程序员编写一些&#8220;中断服务例程&#8221;，主进程的暂停是通过硬件级的中断实现的。尽管这是一种有用的方法，但编出的程序很难移植，由此造成了另一类的代价高昂问题。中断对那些实时性很强的任务来说是很有必要的。但对于其他许多问题，只要求将问题划分进入独立运行的程序片断中，使整个程序能更迅速地响应用户的请求。　　<br style="word-wrap: break-word; " />最开始，线程只是用于分配单个处理器的处理时间的一种工具。但假如操作系统本身支持多个处理器，那么每个线程都可分配给一个不同的处理器，真正进入&#8220;并行运算&#8221;状态。从程序设计语言的角度看，多线程操作最有价值的特性之一就是程序员不必关心到底使用了多少个处理器。程序在逻辑意义上被分割为数个线程；假如机器本身安装了多个处理器，那么程序会运行得更快，毋需作出任何特殊的调校。根据前面的论述，大家可能感觉线程处理非常简单。但必须注意一个问题：共享资源！如果有多个线程同时运行，而且它们试图访问相同的资源，就会遇到一个问题。举个例子来说，两个线程不能将信息同时发送给一台打印机。为解决这个问题，对那些可共享的资源来说（比如打印机），它们在使用期间必须进入锁定状态。所以一个线程可将资源锁定，在完成了它的任务后，再解开（释放）这个锁，使其他线程可以接着使用同样的资源。　<br style="word-wrap: break-word; " />多线程是为了同步完成多项任务，不是为了提高运行效率，而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。<br style="word-wrap: break-word; " />一个采用了多线程技术的应用程序可以更好地利用系统资源。其主要优势在于充分利用了CPU的空闲时间片，可以用尽可能少的时间来对用户的要求做出响应，使得进程的整体运行效率得到较大提高，同时增强了应用程序的灵活性。更为重要的是，由于同一进程的所有线程是共享同一内存，所以不需要特殊的数据传送机制，不需要建立共享存储区或共享文件，从而使得不同任务之间的协调操作与运行、数据的交互、资源的分配等问题更加易于解决（摘自：http://baike.baidu.com/view/65706.htm）<br style="word-wrap: break-word; " />通常由操作系统负责多个线程的调度和执行。<br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><a href="http://blog.chinaunix.net/link.php?url=http://blog.chinaunix.net/attachment/201201/19/20556054_1326963781eH11.png" target="_blank" style="word-wrap: break-word; text-decoration: none; color: #63401b; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; "><img src="http://blog.chinaunix.net/attachment/201201/19/20556054_1326963781eH11.png"  . load="imgResize(this, 650);"  ;="" border="0" style="word-wrap: break-word; border: 0px; max-width: 650px; "  alt="" /></a><br style="word-wrap: break-word; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; background-color: #f5f7f8; " /><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; "><br style="word-wrap: break-word; " /></span></strong></p><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">进程间通信</span></strong><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">（<strong style="word-wrap: break-word; "><span style="word-wrap: break-word; line-height: 1.5; ">IPC</span></strong>，<em style="word-wrap: break-word; "><span style="word-wrap: break-word; line-height: 1.5; ">Inter-Process Communication</span></em>），指至少两个<span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; ">进程</span></span></span>或<span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; ">线程</span></span></span>间传送数据或信号的一些技术或方法。进程是<span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; ">计算机系统</span></span></span>分配资源的最小单位。每个进程都有自己的一部分独立的系统资源，彼此是隔离的。为了能使不同的进程互相访问资源并进行协调工作，才有了进程间通信。这些<span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; ">进程</span></span></span>可以运行在同一计算机上或网络连接的不同计算机上。</span></p><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">进程间通信技术包括消息传递、同步、共享内存和<span style="word-wrap: break-word; line-height: 1.5; ">远程过程调用</span><span style="word-wrap: break-word; line-height: 1.5; ">。IPC</span>是一种标准的<span style="word-wrap: break-word; line-height: 1.5; ">Unix</span>通信机制。</span></p><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">使用<span style="word-wrap: break-word; line-height: 1.5; ">IPC&nbsp;</span>的理由：</span></p><ul type="disc" style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style-position: outside; list-style-image: none; line-height: 24px; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8; "><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; text-align: left; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">信息共享</span></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; text-align: left; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">加速<span style="word-wrap: break-word; line-height: 1.5; ">;</span></span></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; text-align: left; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">模块化<span style="word-wrap: break-word; line-height: 1.5; ">;</span></span></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; text-align: left; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">方便<span style="word-wrap: break-word; line-height: 1.5; ">;&nbsp;</span>以及</span></li><li style="word-wrap: break-word; margin: 0px; padding: 0px 0px 0px 2em; list-style: disc outside none; text-align: left; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">私有权分离<span style="word-wrap: break-word; line-height: 1.5; ">.</span></span></li></ul><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-family: 宋体, Arial; background-color: #f5f7f8; "><strong style="word-wrap: break-word; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 18pt; "><span style="word-wrap: break-word; line-height: 1.5; "></span></span></strong><strong style="word-wrap: break-word; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 18pt; ">主要的<span style="word-wrap: break-word; line-height: 1.5; ">&nbsp;IPC&nbsp;</span>方法</span></strong></p><table border="0" cellpadding="0" style="word-wrap: break-word; color: #000000; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; text-align: start; background-color: #f5f7f8; "><tbody style="word-wrap: break-word; "><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><strong style="word-wrap: break-word; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">方法</span></strong></p></td><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><strong style="word-wrap: break-word; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">提供方（操作系统或其他环境）</span></strong></p></td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">文件</span></p></td><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">多数操作系统</span></p></td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">信号</span></p></td><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">多数操作系统</span></p></td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">Socket</span></p></td><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">多数操作系统</span></p></td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; "><span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; ">消息队列</span></span>(en:Message queue)</span></p></td><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">多数操作系统</span></p></td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; "><span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; ">管道</span></span>(en:Pipe)</span></p></td><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">所有的&nbsp;<span style="word-wrap: break-word; line-height: 1.5; ">POSIX systems, Windows.</span></span></p></td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; "><span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; ">具名管道</span></span>(en:Named Pipe)</span></p></td><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">所有的&nbsp;<span style="word-wrap: break-word; line-height: 1.5; ">POSIX&nbsp;<span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; ">系统</span></span>, Windows.</span></span></p></td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; "><span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; ">信号量</span></span>(en:Semaphore)</span></p></td><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">所有的&nbsp;<span style="word-wrap: break-word; line-height: 1.5; ">POSIX&nbsp;<span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; ">系统</span></span>, Windows.</span></span></p></td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">共享内存</span></p></td><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">所有的&nbsp;<span style="word-wrap: break-word; line-height: 1.5; ">POSIX&nbsp;<span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; ">系统</span></span>, Windows.</span></span></p></td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">Message passing(en:Message passing)<br style="word-wrap: break-word; " />(</span><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">不共享<span style="word-wrap: break-word; line-height: 1.5; ">)</span></span></p></td><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">用于&nbsp;<span style="word-wrap: break-word; line-height: 1.5; ">MPI</span>规范，<span style="word-wrap: break-word; line-height: 1.5; ">Java RMI, CORBA, MSMQ, MailSlot</span>以及其他<span style="word-wrap: break-word; line-height: 1.5; ">.</span></span></p></td></tr><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">Memory-mapped file(en:Memory-mapped file)</span></p></td><td style="word-wrap: break-word; line-height: 1.5; padding: 0.75pt; "><p align="left" style="word-wrap: break-word; margin: 0px; padding: 5px 0px 0px; line-height: 1.5; font-size: 14px; "><span style="word-wrap: break-word; line-height: 1.5; font-family: 宋体; font-size: 12pt; ">所有的&nbsp;<span style="word-wrap: break-word; line-height: 1.5; ">POSIX&nbsp;<span style="word-wrap: break-word; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 1.5; ">系统</span></span>, Windows.</span></span></p></td></tr></tbody></table>（摘自：http://zh.wikipedia.org/wiki/行程間通訊）&nbsp;<br /><br />转自:<a href="http://blog.chinaunix.net/uid-20556054-id-3060696.html">http://blog.chinaunix.net/uid-20556054-id-3060696.html</a><img src ="http://www.cppblog.com/mysileng/aggbug/196401.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-18 13:44 <a href="http://www.cppblog.com/mysileng/archive/2012/12/18/196401.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>