1.在多核CPU下,同一进程下的多个线程可不可以并行运行,是不是一个进程下的所有线程都在同一个cpu上运行?


如果是内核线程(就是fork出来的,pthread_create在2.4后最终也用fork,具体参看其实现),那么可以调度到多cpu,内核支持线程的诱导因素之一就是可以利用多cpu资源进行并行计算;如果是用户线程,那么就不能在多cpu上并行计算了,用户库线程的弊端之一就是不能利用多cpu资源;具体到调度,就是当内核发现本cpu没有任何可运行线程时,就会去别的忙cpu上拽几个下来,当然这是内核自发进行的多cpu调度,作为用户也可以自觉地将线程邦定到具体cpu,更加确定的利用多cpu,当然什么都不是任其发展的,内核不能随便从哪个忙cpu上拽线程,还要看线程愿不愿意(参见linux内核函数cpuset_cpus_allowed),另外还要考虑smt(在intel平台即超线程)的兄弟cpu,还要考虑numa,你总不能让本地cpu的线程跑到遥远的cpu上运行吧…..(还有很多好玩的,自己看代码吧)

以上扯的都是linux的实现,是我对代码的总结,感兴趣可自行阅读。至于windows平台,道道就更多了(windows的道道总是能把你搞晕,不过玩玩挺好,挺有趣,比如动态优先级提升之类的),它甚至可以让内核线程运行在一个专门cpu上,别的用户线程分享别的cpu(linux也可以做到,但是有意思吗?)…..

对于运行在多CPU上的LINUX来说,每个CPU有一个自己的调度队列。当多个调度队列中的进程数相差超过一定的数值时,内核会自动进行调整,从而使得各CPU上的进程数保持均衡。

另外需要说明的是,Linux下的线程,相当于进程,因为它在内核中有自己的task_struct。其实线程与进程的唯一差别是,线程没有自己独立的虚存空间。也就是说,如果一个进程创建了一个线程,那么新线程与老的主线程,就相当于两个共享虚存空间的进程。内核的调度程序是以task_struct为单位进行调度的。

一个进程中的多个线程可以在多核处理器上的 不同核上运行吗?

未必,得看操作系统的支持和调度算法

这得看操作系统怎么管理CPU资源,运行在操作系统上的进程不止一个,每个进程的线程也可能多个。所以操作系统对于是把同一进程的线程分配到不同的CPU,还是在同一个CPU上使用轮训和调度权限改变来调度,这一切都是由操作系统的调度算法决定的

线程应该是一个并发的概念,不是并行的概念吧,并发是指每一时刻仅有一个线程投入运行,并行就不同了每一刻都有N多的线程在同时运行,共享系统资源,如果线程可以在多处理器上运行的话那就是并行了,如果是这样的话,应该是硬件CPU的研制跟不上软件的发展才对(多加线程提升软件的性能),但事实并非如此,

2.进程与线程的一个简单解释引发的讨论

http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html

herodot 说:

进程和线程简单而基本靠谱的定义如下:
1. 进程:程序的一次执行
2. 线程:CPU的基本调度单位
这两个概念虽然过于简单,但是完全可以为理解OS/线程/进程打下坚实的基础,我认为关于进程/线程的探讨,无论采用何种方式,都必须以这两句话为落脚点,才算靠谱。
你写的大多数文章相当出色。在以通俗的方式解释复杂的概念这方面,尤其出色。但是,我个人的经验,这种方式比较适合用来解释一个复杂概念的一个方面,或者从某个角度的理解。想面面俱到的说明白一个复杂的系统,繁琐枯燥的概念,以及这些概念间的推演几乎不可避免。坦白说,在实际项目中大量用到线程/进程之前,我看过很多遍相关的概念,也写过小的示例程序,但真到了用的时候,还是发现之前没搞明白。
我对进程/线程的理解也很粗浅。个人见解,仅供参考。

viho_he 说

抛开各种技术细节,从应用程序角度讲:
1、在单核计算机里,有一个资源是无法被多个程序并行使用的:cpu。
没有操作系统的情况下,一个程序一直独占着全都cpu。
如果要有两个任务来共享同一个CPU,程序员就需要仔细地为程序安排好运行计划–某时刻cpu和由程序A来独享,下一时刻cpu由程序B来独享
而这种安排计划后来成为OS的核心组件,被单独名命为“scheduler”,即“调度器”,它关心的只是怎样把单个cpu的运行拆分成一段一段的“运行片”,轮流分给不同的程序去使用,而在宏观上,因为分配切换的速度极快,就制造出多程序并行在一个cpu上的假象。
2、在单核计算机里,有一个资源可以被多个程序共用,然而会引出麻烦:内存。
在一个只有调度器,没有内存管理组件的操作系统上,程序员需要手工为每个程序安排运行的空间 – 程序A使用物理地址0x00-0xff,程序B使用物理地址0x100-0x1ff,等等。
然而这样做有个很大的问题:每个程序都要协调商量好怎样使用同一个内存上的不同空间,软件系统和硬件系统千差万别,使这种定制的方案没有可行性。
为了解决这个麻烦,计算机系统引入了“虚拟地址”的概念,从三方面入手来做:
2.1、硬件上,CPU增加了一个专门的模块叫MMU,负责转换虚拟地址和物理地址。
2.2、操作系统上,操作系统增加了另一个核心组件:memory management,即内存管理模块,它管理物理内存、虚拟内存相关的一系列事务。
2.3、应用程序上,发明了一个叫做【进程】的模型,(注意)每个进程都用【完全一样的】虚拟地址空间,然而经由操作系统和硬件MMU协作,映射到不同的物理地址空间上。不同的【进程】,都有各自独立的物理内存空间,不用一些特殊手段,是无法访问别的进程的物理内存的。
3、现在,不同的应用程序,可以不关心底层的物理内存分配,也不关心CPU的协调共享了。然而还有一个问题存在:有一些程序,想要共享CPU,【并且还要共享同样的物理内存】,这时候,一个叫【线程】的模型就出现了,它们被包裹在进程里面,在调度器的管理下共享CPu,拥有同样的虚拟地址空间,同时也共享同一个物理地址空间,然而,它们无法越过包裹自己的进程,去访问别一个进程的物理地址空间。
4、进程之间怎样共享同一个物理地址空间呢?不同的系统方法各异,符合posix规范的操作系统都提供了一个接口,叫mmap,可以把一个物理地址空间映射到不同的进程中,由不同的进程来共享。
5、PS:在有的操作系统里,进程不是调度单位(即不能被调度器使用),线程是最基本的调度单位,调度器只调度线程,不调度进程,比如VxWorks