您的位置:首页 > 其它

《现代操作系统》第2章 进程与线程

2017-04-05 16:50 183 查看
1.  进程
一个正在执行的程序实例

2.  进程模型
概念上每个进程拥有自己的虚拟CPU,实际上真正的CPU在各进程之间来回切换(多道程序设计)

3.  创建进程
1) 系统初始化

2) 执行了正在运行的进程所调用的进程创建系统调用fork()

3) 用户请求创建一个新进程

4) 一个批处理作业的初始化

4.  进程终止
1) 正常退出(自愿的)

2) 出错退出(自愿的)

3) 严重错误(非自愿)

4) 被其他进程杀死(非自愿)

5.  进程的层次结构
UNIX:进程与其子进程构成一个进程组

WINDOWS:没有层次概念,父进程用句柄控制子进程

6.  进程状态



运行、阻塞、就绪

1) 运行->阻塞:进程为等待输入而阻塞

2) 运行->就绪:调度程序选择另一个进程

3) 就绪->运行:调度程序选择这个进程

4) 阻塞->就绪:出现有效输入

其他状态:挂起、终止

7.  进程的实现
进程表表项(进程控制块)包括与进程管理、存储管理、文件管理有关的信息。

中断向量:中断发送时,保存状态后,计算机跳转到中断向量所指示位置完成操作。

多道程序设计中的CPU利用率=1-p^n

(n进程数,p用于I/O操作的时间与等待时间的时间比)

8.  线程(迷你进程)
9.  进程与线程内容的比较
进程:

地址空间

全局变量

打开文件清单

子进程

即将发生的报警

信号与信号处理程序

账号信息

线程:

程序计数器

寄存器

堆栈

状态

 

一组线程共享资源

两种主要方法实现进程包:在用户空间中和在内核中(另有混合实现)

10. 内核级线程的调度程序激活机制
目的:模拟内核级线程的功能,提供(在用户空间才能实现的)更好的性能和更大的灵活性,避免了不必要的用户空间/内核空间转换,提高效率。

内核给每个进程安排一定数量的虚拟处理器,将线程分配的处理器上

11. 弹出式线程
分布式系统中另一种处理消息到来的方式,一个消息的到达导致系统创建一个处理该消息的程序。

12. 进程间通信
竞争条件:两个或多个进程读写共享数据,最后结果取决于进程运行的精确时序

临界区:对共享内存进行访问的程序片段

避免竞争条件需满足以下4个条件:

1)    任何两个进程不能同时处于临界区

2)    不应对CPU数量和速度做任何假设

3)    临界区外运行的进程不得阻塞其他进程

4)    不得使进程无限期等待进入临界区

13. 实现忙等待的互斥的方案
1)    屏蔽中断

2)    锁变量

3)    严格轮换法(忙等待)

4)    Peterson解法

5)    TSL指令(需要硬件支持,“测试并加锁”指令)

14. 信号量
用一个整型变量累计唤醒次数

P/down:大于0,减1;为0,将进程睡眠

V/up:增1。

整个操作是不可分割的原子操作

15. 使用信号量解决“生产者-消费者问题”
(1)含有严重竞争条件的生产者-消费者问题(下面代码)

对count的访问未加限制。

有可能出现以下情况:缓冲区为空,消费者刚刚读取count的值发现它为0。此时调度程序把 CPU切换给了生产者。生产者想缓冲区中加入一个数据项,count加1,并且它推断由于刚才count为0,所以消费者一定在睡眠,所以调用 wakeup来唤醒消费者。但消费者并未睡眠,所以wakeup信号丢失。当消费者下次运行时,它将测试先前读到的count值,发现为0,于是睡眠。生 产者迟早会填满整个缓冲区,然后睡眠。最后两个进程都将永远睡眠下去。

#define N 100 /*缓冲区中的槽数目*/
int count = 0; /*缓冲区中的数据项数目*/
void producer(void)
{
int item;
while(TRUE)
{
item=produce_item();
if(count==N) sleep();
insert_item(item);
count=count+1;
if(count==1) wakeup(consumer); /*count==1说明生产之前count==0,consumer进程应该在睡眠,遂唤醒它*/
}
}

void consumer(void)
{
int item;
while(TRUE)
{
if(count==0) sleep();
item=remove_item();
count=count-1;
if(count==N-1) wakeup(producer); /*count==N-1说明消费之前缓冲区满了,生产者应该在睡眠,遂唤醒*/
consume_item(item);
}
}

 
(2)使用信号量解决“生产者-消费者问题”

信号量mutex用于互斥,保证任意时刻只有一个进程读写缓冲区和相关变量。互斥是避免混乱所必需的操作。

信号量full和empty用于实现同步,保证某种事件的顺序发生或不发生。它们保证当缓冲区满的时候生产者停止运行,以及当缓冲区空的时候消费者停止运行。

#define N 100 /*缓冲区中的槽数目*/
typedef int semaphore; /*信号量是一种特殊的整型数据*/
semaphore mutex = 1; /*控制对临界区的访问*/
semaphore empty = N; /*计数缓冲区的空槽数目*/
semaphore full=0; /*计数缓冲区的满槽数目*/

void producer(void)
{
int item;
while(TRUE)
{
item=produce_item();
down(&empty); /*空槽数目减一*/
down(&mutex); /*进入临界区*/
insert_item(item);
up(&mutex); /*离开临界区*/
up(&full); /*将满槽的数目加1*/
}
}

void consumer(void)
{
int item;
while(TRUE)
{
down(&full);
down(&mutex);
item=remove_item();
up(&mutex);
up(&empty);
consume_item(item);
}
}

16. 互斥量
一个二进制位(解锁和加锁),是信号量的简化版本。

17. 利用线程解决“生产者-消费者问题”
#include <stdio.h>
#include <pthread.h>
#define MAX 10 //需要生产的数量
pthread_mutex_t the_mutex;
pthread_cond_t condc, condp;
int buffer = 0;//生产者、消费者使用的缓冲区

void *producer(void *ptr)
{
int i;
for(i=1; i<=MAX; i++)
{
pthread_mutex_lock(&the_mutex); //互斥使用缓冲区
while(buffer !=0) pthread_cond_wait(&condp, &the_mutex);
printf("procucer produce item %d\n",i);
buffer = i; //将数据插入缓冲区
pthread_cond_signal(&condc);//唤醒消费者
pthread_mutex_unlock(&the_mutex);//释放缓冲区
}

pthread_exit(0);

}

void *consumer(void *ptr)
{

int i;
for(i=1; i<=MAX; i++)
{
pthread_mutex_lock(&the_mutex);//互斥使用缓冲区
while(buffer ==0) pthread_cond_wait(&condc, &the_mutex);
printf("consumer consume item %d\n",i);
buffer = 0;//从缓冲区中取出数据
pthread_cond_signal(&condp);//唤醒生产者
pthread_mutex_unlock(&the_mutex);//释放缓冲区
}
pthread_exit(0);

}

int main(int argc, char *argv[])
{
pthread_t pro, con;
pthread_mutex_init(&the_mutex, 0);
pthread_cond_init(&condc,0);
pthread_cond_init(&condp,0);
pthread_create(&con, 0, consumer, 0);
pthread_create(&pro, 0, producer, 0);
pthread_join(pro,0);
pthread_join(con,0);
pthread_cond_destroy(&condc);
pthread_cond_destroy(&condp);
pthread_mutex_destroy(&the_mutex);
return 0;
}

18. 其它同步机制
(1)管程

高级同步原语,一个管程是一个有过程、变量及数据结构等组成的一个集合,组成一个特殊模块或软件包。

任一时刻管程中只能有一个进程。

(2)消息传递

(3)屏障:除非所有的进程都就绪准备下一阶段,否则任何进程都不能进入下一阶段。

 

19. 调度
选择下一个占用资源的进程。

何时调度:

1) 创建新进程后

2) 一个进程退出时

3) 一个进程阻塞时

4) 发生I/O中断时

5) 时钟中断时

调度算法的目标:公平、策略强制性、平衡

调度算法的分类:抢占式/非抢占式

三种环境:

1) 批处理(吞吐量、周转时间、CPU利用率)

2) 交互式(响应时间、均衡性)

3) 实时(满足截止时间、可预测性)

20. 调度算法
批处理:

1)先来先服务

2)最短作业优先

3)最短剩余时间优先

交互式:

1)轮转调度(分时间片,每个进程在一个时间片内运行)

2)优先级调度

3)多级队列(前两种结合)

4)最短进程优先(老化算法估计运行时间aT0+(1-a)T1,如a=1/2,时间序列为T0,T0/2+T1/2,T0/4+T1/4+T2/2,三轮过后T0在新的估计值中所占的比重下降到1/8)

5)保证调度

6)彩票调度

7)公平分享调度(保证用户分配到的CPU时间的公平)

实时:

硬实时/软实时

周期性/非周期性

21. 哲学家就餐问题的一种解法
#define N 5 /*哲学家数目*/
#define LEFT (i-1+N)%N /*i的左邻号码*/
#define RIGHT (i+1)%N /*i的右邻号码*/
#define THINKING 0 /*哲学家正在思考*/
#define HUNGRY 1 /*哲学家想取得叉子*/
#define EATING 2 /*哲学家正在吃面*/
typedef int semaphore; /*信号量是一个特殊的整型变量*/
int state
; /*记录每个人状态的数组*/
semaphore mutex = 1; /*临界区互斥*/
semaphore s
; /*每个哲学家一个信号量*/

void philosopher(int i) { /*i:哲学家号码,从0到N-1*/
while(TURE){ /*无限循环*/
think(); /*哲学家正在思考*/
take_forks(i); /*需要两只叉子,或者阻塞*/
eat(); /*进餐*/
put_forks(i); /*把两把叉子同时放回桌子*/
}
}

void take_forks(int i) { /*i:哲学家号码,从0到N-1*/
down(&mutex); /*进入临界区*/
state[i]= HUNGRY; /*记录下哲学家i饥饿的事实*/
test(i); /*试图得到两只叉子*/
up(&mutex); /*离开临界区*/
down(&s[i]); /*如果得不到叉子就阻塞*/
}

void put_forks(int i) { /*i:哲学家号码,从0到N-1*/
down(&mutex); /*进入临界区*/
state[i]= THINKING; /*哲学家进餐结束*/
test(LEFT); /*看一下左邻居现在是否能进餐*/
test(RIGHT); /*看一下右邻居现在是否能进餐*/
up(&mutex); /*离开临界区*/
}

void test(i) { /*i:哲学家号码,从0到N-1*/
if(state[i]== HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING) {
state[i]= EATING;
up(&s[i]);
}
}
22. 读者写者问题的一种解法
typedef int semaphore; /*定义整型的信号量*/
semaphore mutex = 1; /*为控制对全局量rc的访问而设置的信号量*/
semaphore db = 1; /*为控制对数据库的访问而设置的信号量*/
int rc = 0; /*rc是正在读或者等待读的进程数,初值为0*/

void reader(void)
{
while(TRUE) { /*设置无限循环方式*/
down(&mutex); /*获取对rc变量的互斥访问权*/
rc= rc + 1; /*这时又多了一个读进程*/
if(rc == 1) down(&db); /*若是第一个读者,则允许访问*/
up(&mutex); /*释放对rc的互斥操作*/
reader_data_dase(); /*完成数据访问操作*/
down(&mutex); /*获取对rc变量的互斥访问权*/
rc= rc - 1; /*这时减少了一个读者进程*/
if(rc == 0) up(&db);/*若是最后一个读者,可允许写*/
up(&mutex); /*释放对rc的互斥访问*/
use_data_read(); /*非临界区操作,使用读出数据*/
}
}
void writer(void)
{
while(TRUE) { /*设置无限循环方式*/
think_up_data(); /*非临界区操作,准备希望修改的数据*/
down(&db); /*获取数据库互斥访问权*/
writer_data_dase; /*更新数据库消息*/
up(&db); /*释放数据库互斥访问权*/
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息