系统+线程+进程

分时操作系统(time sharing system)

一台计算机挂有若干终端, 每个终端提供给一个用户,不同用户通过自己的终端访问系统。

系统将处理器的时间分割成很小的时间段(时间片),系统以时间片为单位,交替为终端服务,但是用户的感觉就像是系统一直在为本终端服务。

假如计算机只有一个内核,那么如果想运行两个进程的话,就要用时间片,某一时刻只有一个进程在运行,如果系统有多个内核的话,在同一时间就可以有两个进程在

运行,但是同一时间运行的进程数不能超过cpu的核数,如果某一个进程的线程比较多,则会调用其它核来运行当前核上进程的线程,所以并不是严格的一个核只运行一个进程。

一个进程(程序)不可能只访问cpu资源,肯定会跟计算机资源打交道,比如读文件,查数据库,访问网络。。。。多线程的好处就体现出来了

比如在线程a用cpu执行一个读文件的命令,然后线程a就去读文件了(可能比较久),此时cpu是空闲的,所以可以用来让线程b去查数据库,等b在查询的时候,又可以让

线程c去访问网络.....


典型代表:unix, linux

进程与线程(process and thead)

进程是正在运行的程序的抽象

当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存及系统资源

*程序是一组指令的几何,他静态存储在存储器中(磁盘)

*当程序被操作系统执行时,它被载入内存,并在逻辑上产生了一个独立的实例,就是进程

好像:程序是菜谱,其中的指令就是指挥火候调料的步骤;进程就是烹饪的过程,操作系统按指令烹饪

            得到的结果就是菜肴

线程是进程的一个实例,是操作系统进行调度的独立单位

线程又称为:轻量级进程(light weight process:LWP),线程过多,内存消耗越大。

多进程是内存中同时存放多个程序,这些程序在管理程序(用户sleep,或者系统的时间轮片)的控制下交替的在cpu上执行,某一时刻只有一个进程在执行,宏观看是cpu“同时”执行了多个进程。

程序并发执行,共享系统资源,资源的使用状态受所有并发程序的共同影响,由于程序执行相对速度不确定,所以程序何时执行,转换等,受系统当时环境影响,有一定随机性

共享的程序可以被多个用户作业调度

执行时所以程序相互制约,执行过程不是顺序的,而是“执行-暂停-执行”

进程状态

运行,在cpu中正在执行,处于运行状态的进程数目不能超过cpu的个数

就绪,具备执行条件,可以到cpu中运行,但是cpu被占用了

阻塞(se),等待某一事件而不能运行,不具备执行条件,即使cpu空闲也不能到cpu中运行

新建,刚被创建,还没放到就绪队列当中的状态

终止,不能再被调用,被系统撤销

进程状态转换

就绪->运行(如果正在运行的因为某一事件不能执行了,阻塞;则会调用一个就绪的来执行)原因:运行->阻塞

运行->就绪(用于执行该进程的时间片用完了,变为就绪等待下一次时间片)

阻塞->就绪(等待的事情完成了,则阻塞的进程就相当于就绪了,如果cpu空闲则可以去执行)

进程控制块(process control block, PCB)

记录进程的动态特性,操作系统根据PCB对进程进行控制和管理。进程由程序段,数据段,进程控制快组成。

进程是马路,线程是车道

内核级线程

内核为应用程序提供了一个API,调用API实现线程的创建和控制管理

用户级线程

线程的创建,撤销及切换都不利用系统调度,这种线程与内核无关。内核处理的对象是进程,用户处理的是线程。

一个类比

计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。


假定工厂的电力有限,一次只能供给一个车间使用。也就是说,一个车间开工的时候,其他车间都必须停工。

背后的含义就是,单个CPU一次只能运行一个任务。


进程就好比工厂的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。


一个车间里,可以有很多工人。他们协同完成一个任务。


线程就好比车间里的工人。一个进程可以包括多个线程。


车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征一个进程的内存空间是共享的,

每个线程都可以使用这些共享内存。


可是,每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面有人的时候,其他人就不能进去了。

这代表一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。


一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。

这就叫"互斥锁"(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。


还有些房间,可以同时容纳n个人,比如厨房。也就是说,如果人数大于n,多出来的人只能在外面等着。

这好比某些内存区域,只能供给固定数目的线程使用。这时的解决方法,就是在门口挂n把钥匙。

进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。

这种做法叫做"信号量"(Semaphore),用来保证多个线程不会互相冲突。

不难看出,mutex是semaphore的一种特殊情况(n=1时)。也就是说,完全可以用后者替代前者。

但是,因为mutex较为简单,且效率高,所以在必须保证资源独占的情况下,还是采用这种设计。

操作系统的设计,因此可以归结为三点:

(1)以多进程形式,允许多个任务同时运行;

(2)以多线程形式,允许单个任务分成不同的部分运行;

(3)提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源。

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

编程:

1.一个进程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程

返回错误(代码:ESRCH)

2.互斥锁(保证一段时间内只有一个线程在执行一段代码)

pthread_mutex_int生成一个互斥锁

pthread_mutex_lock用互斥锁上锁,此后的代码调用到pthread_mutex_unlock位置,均被上锁,被上锁的

代码在某一时间只能由一个线程来调用执行。如果另一个线程B执行到pthread_mutex_lock时候,则B阻塞(等待其他进程完成,阻塞->就绪)。

3.pthread_create(线程标识符指针,线程属性指针,线程运行函数指针,运行函数的参数指针);

创建成功返回0,否则就是创建失败

void *thr_fun(void *arg){...; return ((void *)0);或者return NULL;}

4.输出线程标识符

printf("pid %u tid %u (0x%x)\n",(unsigned int)getpid(),(unsigned int)pthread_self(),(unsigned int)pthread_self());

5.编译多线程时候:gcc example.c -lpthread -o example.o

6.  多线程数据:线程内类似于全局变量,对线程外的其他线程不可见

多线程程序中:局部变量,全局变量,线程数据(Thread-Specific Data:TSD)

如:errno,不是一个局部变量,因为几乎每一个函数可以调用;但是也不能是一个全局变量,否则

A线程里输出的可能是B线程的粗错信息。所以就要用线程数据。

键<->线程数据     非线程程序,就是全局变量;线程程序,用键指代TSD,但是不同线程键值又不一样

相关函数:创建键,绑定键,读取键,删除键

extern int pthread_key_create_P+pthread_once配合保证键只被创建一次

pthread_key_t  key;  pthread_once_t  once;   void fun(void*);   void freefun(void*);

pthread_once(&once,fun);   pthread_setspecific(key,fun);   pthread_keycreate(&key,freefun);

在不同线程中通过pthread_getspecific(key);获取fun这个STD。

7.互斥锁:共享资源和多线程(没有共享资源则无需加锁,如果是单线程也不需要加锁)

共享资源在代码中可以是:文件,全局变量,堆内存等;多线程反映在代码中是重叠执行的代码段

一个加锁或者解锁的时间大概占用100个机器周期(http://www.rosoo.net/a/201009/10101.html)

互斥量的使用流程应该是:线程占用互斥量,然后访问共享资源,最后释放互斥量。而不应该是:线程占用互斥量,然后判断资源是否可用,如果不可用,释放互斥量,然后重复上述过程。这种行为称为轮转或轮询,是一种浪费CPU时间的行为。

mutex锁住的不是一个变量,而是阻塞一段程序。......pthread_mutex_lock(&locker);//code fragment pthread_mutex_unlock(&loker);执行第一次之后,在unlock之前,其他线程执行到pthread_mutex_lock时候就会阻塞,直到之前的unlock之后才能执行。

void *read(void*); void *write(void*);

pthread_mutex_t  mutex;

void main()

{pthread_t id; pthread_mutex_init(&mutex,NULL); pthread_create(&id,NULL,read,NULL);write();}

void *write(void*){pthread_mutex_lock(&mutex); //write pthread_mutex_unlock(&mutex); sleep(100);}

void *read(void*){pthread_mutex_lock(&mutex); //read pthread_mutex_unlock(&mutex); sleep(100);}

死锁:线程A,B都要锁定互斥锁m1,m2   假如A先锁m1,B先锁m2,就出现了死锁。

8.条件变量:用于进行线程间的同步

9.sleep()和pthread_join()

sleep让当前使用cpu的线程挂起,交出cpu的使用权,则其他等待cpu的线程就可以执行了。

除了用户指定线程挂起(sleep),还有就是系统的时间轮片,如果一个线程执行的太久了,那么系统控制的

时间到了后,系统会让它挂起,这时候其他就绪的线程就会执行。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值