会飞的猪

一生偏执成今日

操作系统的进程与线程

程序设计实践中图12.8说道:

线程调度器在库或者语言的运行系统里实现,多路线程在一个或几个内核层的进程上运行。就像进程调度器在操作系统内核里实现,多路进程在一个或几个物理处理器上运行。

http://stackoverflow.com/questions/807506/threads-vs-processes-in-linux,说的是Linux内核2.6版本后的情况

http://www.unobvious.com/bsd/freebsd-threads.html 给予了freebsd系统中进程与线程的一个比较详细的说明。

http://tldp.org/FAQ/Threads-FAQ/Types.html 这篇文章说明了2.4以前的linux threads。

http://java.sun.com/docs/hotspot/threads/threads.html 这篇讲解了solaris.

我们常说的多线程处理器,《计算机体系结构一种量化方法》中,对这个线程的定义有一个清晰的解释:

This higher-level parallelism is called thread-level parallelism (TLP) because
it is logically structured as separate threads of execution. A thread is a separate
process with its own instructions and data. A thread may represent a process that
is part of a parallel program consisting of multiple processes, or it may represent
an independent program on its own. Each thread has all the state (instructions,
data, PC, register state, and so on) necessary to allow it to execute.

可见此线程非彼线程。

另外,还需分清内核调度实体、进程和线程三组定义,在这里或可认为进程不过是系统分配的一组资源组合,而线程则是一个执行上下文。那么内核调度的便未必一定是进程,也未必一定是线程。

我们常识中的线程实际应分为用户线程和系统线程两种,用户线程由应用程序调度,内核并不知道它的存在,好处是切换时不需要在内核态和用户态切换,开销很小,坏处是容易导致饥饿现象等。

系统线程由内核调度,应用程序不用管调度,因而资源分配较好,坏处是切换开销较大。

那么Linux和Windows分别是如何实现的呢?

Linux系统2.6内核中,很难用我们常识中的进程和线程去定义,内核能够调度的实体是kernel threads,那么进程就是一组共享部分资源以及拥有一个 thread group id的LWP,而LWP则是对kernel thread的包装,1:1。fork和pthread不过是对clone调用的一个包装,调用时赋予clone参数来决定是否共享所需的空间,产生的都是LWP。

为了使用lwp,必须有相应的库,所以NPTL实现的其实是1:1,每一个用户线程对应一个LWP。而gnu portable threads实现的是N:1,多个用户线程对应一个LWP。前者可通过内核对系统线程的调度来对用户线程调度,后者必须自己有一个调度器。

Linux2.4以前并没有NPTL,而其他的*nix系统的线程库也多为用户线程,modern *nix system多已实现了NPTL的机制或移植了NPTL。

并不是所有的*nix系统都有LWP这一层的包装,下面是从wikipedia中的摘录:

In the traditional meaning of the term, as used in Unix System V and Solaris, a LWP runs in user space on top of a single kernel thread and shares its address space and system resources with other LWPs within the same process. Multiple user level threads, managed by a thread library, can be placed on top of one or many LWPs – allowing multitasking to be done at the user level, which can have some performance benefits.[1]

In some operating systems there is no separate LWP layer between kernel threads and user threads. This means that user threads are implemented directly on top of kernel threads. In those contexts, the term “light-weight process” typically refers to kernel threads and the term “threads” can refer to user threads.[2]

windowsNT中,调度的单元是线程,即系统级线程,然而仍有传统上进程的概念,当某个进程被调度到cpu上执行时,通过它的就绪线程列表来调度可执行的线程。另外windowsnt中有了fiber的概念,fiber其实可看做是协程的实现,用户级,系统不知道它的存在,因而只能由用户应用程序调度,自然同时间只能运行一个纤程。

协程的概念最初难以理解,但现在考虑到线程也不过是各种不同的实现,就好理解多了。另外关于协程的解释,wikipedia上说汇编可以原生实现,而c需要通过setjmp和longjmp命令,或setcontext函数。其他不少高级语言内置了支持。按本篇文章的开头,我们可以这样考虑,某种语言在操作系统的调度实体之上实现了用户线程机制,那么同样可在这种系统的调度实体之上实现协程机制。Linux中的各种线程库,不过是用c语言实现的,恰好与操作系统所实现的语言相同而已。

ubuntu 10.10安装ruby 1.9.2 和rails 3.1.1

参考教程包括官方文档,以及:
http://ihower.tw/rails3/index.html
http://skattagun.blogspot.com/2010/09/source-installation-of-ruby-in-ubuntu.html

实际安装过程中出现如下几个问题:
1.如果不安装sqllite直接使用mysql的话,需指明 rails new appname -d mysql,否则
会出错。默认使用的数据库可在某全局变量中更改,具体可查参考手册。
2.gem update -system貌似会有bug,导致已安装的包的时间格式有问题。
3.ubuntu内置没有js的解析器,需在gemfile里指定gem ‘therubyracer’或其他
4.ubuntu编译ruby前需安装一些dev包,尤其是libreadline-dev,否则下文的autocompletion
无法正常使用。参见http://www.ruby-forum.com/topic/230868
5.gem install可能会出现找不到包的错误,原因是超时,方法是换一个时间段下载
6.bundle install有时会要求输入sudo密码,因其下载的包要放在/usr/local下,因而官方推荐
使用rvm来避免这个问题

irb的autocompletion:
首先gem install bond
然后编辑~/.irbrc,加入 require ‘bond’ 以及Bond.start两行