\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}