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