283 lines
8.4 KiB
TeX
283 lines
8.4 KiB
TeX
\documentclass[全部作业]{subfiles}
|
||
\input{mysubpreamble}
|
||
\begin{document}
|
||
\setcounter{chapter}{1}
|
||
\chapter{进程与线程}
|
||
\begin{enumerate}
|
||
\questionandanswer[]{
|
||
设有一台计算机,有两条 I/O 通道,分别挂一台输入机和一台打印机。若要把输入机上的数据逐一地输入到缓冲区 B1 中,然后处理,并把结果搬到缓冲区B2中,最后在打印机上输出。请问:
|
||
}{}
|
||
\begin{enumerate}
|
||
\questionandanswer[]{
|
||
系统可设置哪些进程完成这一任务?这些进程间有什么具体制约关系?
|
||
}{
|
||
\noindent
|
||
进程一:把输入机上的数据逐一地输入到缓冲区 B1 中;\\
|
||
进程二:从缓冲区 B1 中取数据,处理后把结果放到缓冲区B2中;\\
|
||
进程三:从缓冲区 B2 中取数据,在打印机上输出。
|
||
|
||
这里的“逐一地”“缓冲区”等关键词表明是单个缓冲区而不是缓冲队列。那么进程一和进程二之间关于缓冲区B1存在同步的制约关系,进程二和进程三之间关于缓冲区B2存在同步的制约关系。(这里不需要互斥)
|
||
}
|
||
\questionandanswer[]{
|
||
用 P-V 操作写出这些进程的同步算法。
|
||
}{}
|
||
{\kaishu\noindent
|
||
\begin{minipage}{0.4\linewidth}
|
||
\begin{minted}{C}
|
||
struct semaphore B1_empty = 1, B1_full = 0, B2_empty = 1, B2_full = 0;
|
||
number temp1, temp2, temp3;
|
||
buffer B1, B2;
|
||
cobegin
|
||
void process1() {
|
||
while(1) {
|
||
temp1 = input();
|
||
P(B1_empty);
|
||
B1 = temp1;
|
||
V(B1_full);
|
||
}
|
||
}
|
||
void process2() {
|
||
while(1) {
|
||
P(B1_full);
|
||
temp2 = B1_full;
|
||
V(B1_empty);
|
||
temp2 = processing(temp2);
|
||
P(B2_empty);
|
||
B2_full = temp2;
|
||
V(B2_full);
|
||
}
|
||
}
|
||
void process3() {
|
||
while(1) {
|
||
P(B2_full);
|
||
temp3 = B2_full;
|
||
V(B2_empty);
|
||
output(temp3);
|
||
}
|
||
}
|
||
coend
|
||
\end{minted}
|
||
\end{minipage}
|
||
% \columnbreak
|
||
\begin{minipage}{0.6\linewidth}
|
||
\includexopp{2.1.2.1}
|
||
\end{minipage}
|
||
}
|
||
\questionandanswer[]{
|
||
用Send和Receive原语写出这些进程的同步算法。
|
||
}{}
|
||
{\kaishu\noindent
|
||
\begin{minipage}{0.4\linewidth}
|
||
\begin{minted}{C}
|
||
cobegin
|
||
void process1() {
|
||
number item;
|
||
message m;
|
||
while (1) {
|
||
item = input();
|
||
m = build_message(item);
|
||
Send(process2, &m);
|
||
}
|
||
}
|
||
void process2() {
|
||
number item;
|
||
message m;
|
||
while (1) {
|
||
Receive(process1, &m);
|
||
item = extract_item(&m);
|
||
item = processing(item);
|
||
m = build_message(item);
|
||
Send(process3, &m);
|
||
}
|
||
}
|
||
void process3() {
|
||
number item;
|
||
message m;
|
||
while (1) {
|
||
Receive(process2, &m);
|
||
item = extract_item(&m);
|
||
output(item);
|
||
}
|
||
}
|
||
coend
|
||
\end{minted}
|
||
\end{minipage}
|
||
% \columnbreak
|
||
\begin{minipage}{0.6\linewidth}
|
||
\includexopp{2.1.3.1}
|
||
\end{minipage}
|
||
}
|
||
\end{enumerate}
|
||
|
||
\questionandanswer[]{
|
||
“哲学家就餐问题”除课堂上介绍的方案外,有没有其他解决方案?有的话,请
|
||
写出相应的解决方案。
|
||
}{}
|
||
{\kaishu
|
||
有,比较容易想到的一种最简单的方案是,每次只允许一个哲学家就餐,也就是将所有的叉子视为一个整体的临界资源,但是缺点也很明显,会导致性能低下,因为五个叉子可以满足两个哲学家同时就餐。因此下面使用另一种方案。
|
||
|
||
大致方案是偶数序号的哲学家先拿左边的叉子,奇数序号哲学家先拿右边的叉子(释放的时候就不需要讲究先放左边还是先放后边了)。
|
||
% \begin{multicols}{2}
|
||
\begin{minted}{C}
|
||
struct semaphore forks[5] = {1, 1, 1, 1, 1};
|
||
void philosopher(i) {
|
||
while (1) {
|
||
think;
|
||
if (i % 2) {
|
||
P(forks[(i + 1) % 5]);
|
||
P(forks[i])
|
||
} else {
|
||
P(forks[i]);
|
||
P(forks[(i + 1) % 5]);
|
||
}
|
||
eat;
|
||
V(forks[i]);
|
||
V(forks[(i + 1) % 5]);
|
||
}
|
||
}
|
||
\end{minted}
|
||
% \end{multicols}
|
||
}
|
||
\questionandanswer[]{
|
||
a,b两点之间是一段东西向的单行车道,现要设计一个自动管理系统,管理的
|
||
规则如下:当a,b之间有车辆在行驶时同方向的车可以同时驶入a,b段,但另一个
|
||
方向的车必须在a,b段以外等待;当a,b之间无车辆在行驶时,到达a点(或b点)
|
||
的车辆可以进入a,b段,但不能同时驶入;当某方向在a,b段行驶的车辆驶出了a,
|
||
b 段且暂无车辆进入a,b段时,应让另一方向等待的车辆进入a,b段行驶。请用PV
|
||
操作作为工具,对a,b段实现正确管理以确保行驶安全。
|
||
}{}
|
||
{\kaishu
|
||
可能会存在一个问题,就是一个方向一直有车辆,导致另一个方向无法进入车道,从而产生很长的排队。
|
||
|
||
还有个问题,是否要考虑车辆排队的过程,即先入先出,或先排队先进入。
|
||
|
||
这里先不考虑这两个问题。
|
||
|
||
这种问题大多数做法都是使用两个互斥量和两个计数值,这里尝试使用一个互斥量和一个计数值,计数值为正表示从a到b有车辆,计数值为负表示从b到a有车辆。但是缺点是发生任何一个事件(a或b方向进入或离开车辆)都需要访问临界资源(使用同一个 \mintinline{C}{mutex} 信号量),可能会导致性能较低。
|
||
|
||
\begin{multicols}{2}
|
||
\begin{minted}{C}
|
||
struct semaphore mutex = 1, s = 1;
|
||
// 车道内的车辆数
|
||
int count = 0; // 正数为从a到b,负数为从b到a
|
||
cobegin
|
||
void a_to_b() {
|
||
P(mutex);
|
||
if (count <= 0) {
|
||
P(s);
|
||
}
|
||
count++;
|
||
V(mutex);
|
||
通过 a -> b;
|
||
P(mutex);
|
||
count--;
|
||
assert(count >= 0);
|
||
if (count == 0) {
|
||
V(s);
|
||
}
|
||
V(mutex);
|
||
}
|
||
|
||
|
||
void b_to_a() {
|
||
P(mutex);
|
||
if (count >= 0) {
|
||
P(s);
|
||
}
|
||
count--;
|
||
V(mutex);
|
||
通过 b -> a;
|
||
P(mutex);
|
||
count++;
|
||
assert(count <= 0);
|
||
if (count == 0) {
|
||
V(s);
|
||
}
|
||
V(mutex);
|
||
}
|
||
coend
|
||
\end{minted}
|
||
\end{multicols}
|
||
}
|
||
\questionandanswer[]{
|
||
假定有三个进程R、W1、W2共享一个缓冲区B,B中每次只能存放一个整数。
|
||
进程R每次启动输入设备读一个整数且把它存放在缓冲区B中,若存放到缓冲区B中
|
||
的是奇数,则由进程W1将其取出打印,否则由进程W2将其取出打印。要求用PV操
|
||
作管理这3个并发进程,使它们能够正确同步工作。
|
||
}{}
|
||
{\kaishu
|
||
这里使用了三个信号量实现R与W1的同步、R与W2的同步,一个信号量实现了打印的互斥。
|
||
|
||
\begin{minipage}{0.4\linewidth}
|
||
\begin{minted}{C}
|
||
struct semaphore odd = 0, even = 0, empty = 1;
|
||
struct semaphore output_mutex;
|
||
buffer B;
|
||
cobegin
|
||
void R() {
|
||
int temp;
|
||
while (1) {
|
||
temp = input();
|
||
P(empty);
|
||
B = temp;
|
||
if (temp % 2) {
|
||
V(odd);
|
||
} else {
|
||
V(even);
|
||
}
|
||
}
|
||
}
|
||
void W1() {
|
||
int temp;
|
||
while (1) {
|
||
P(odd);
|
||
temp = B;
|
||
V(empty);
|
||
P(output_mutex);
|
||
output(temp);
|
||
V(output_mutex);
|
||
}
|
||
}
|
||
void W2() {
|
||
int temp;
|
||
while (1) {
|
||
P(even);
|
||
temp = B;
|
||
V(empty);
|
||
P(output_mutex);
|
||
output(temp);
|
||
V(output_mutex);
|
||
}
|
||
}
|
||
coend
|
||
\end{minted}
|
||
\end{minipage}
|
||
\begin{minipage}{0.6\linewidth}
|
||
\includexopp{2.4.1}
|
||
\end{minipage}
|
||
}
|
||
\questionandanswer[]{
|
||
假定在一个CPU上执行以下5个作业:(优先数小者优先级高)
|
||
|
||
\begin{center}
|
||
\begin{tabular}{|c|c|c|c|c|c|}
|
||
\hline
|
||
作业号 & 1 & 2 & 3 & 4 & 5 \\
|
||
\hline
|
||
到达时间 & 0 & 2 & 4 & 6 & 8 \\
|
||
\hline
|
||
优先数 & 4 & 3 & 5 & 2 & 1 \\
|
||
\hline
|
||
运行时间 & 3 & 6 & 4 & 5 & 2 \\
|
||
\hline
|
||
\end{tabular}
|
||
\end{center}
|
||
|
||
当分别采用FCFS、RR(时间片为1)、非抢占式SJF、抢占式SJF、优先级调度5
|
||
种调度算法时,试(1)画出调度图(2)计算每个作业的周转时间(3)计算平均周转
|
||
时间。
|
||
}{
|
||
\includexopp{2.5.1}
|
||
}
|
||
\end{enumerate}
|
||
\end{document} |