模拟卷 操作系统 进程和线程进程概念 解答题
第 45 题

(7 分)兄弟俩共同使用一个账号,每次限存或取 10 元,存钱与取钱的进程分别如下所示:

由于兄弟俩可能同时存钱和取钱,因此这两个进程是并发的。若哥哥先存了两次钱,但在第三次存钱时,弟弟在取钱。请问:

(1)最后账号 amount 上面可能出现的值? (2)如何用 P、V 操作实现两并发进程的互斥执行?

进程和线程 进程概念

[tag_link]

**【答案】** (1)最后账号 `amount` 可能出现的值为 10、20 或 30。 (2)使用 P、V 操作实现互斥:定义一个信号量 `mutex` 并初始化为 1。在存钱进程 `SAVE()` 和取钱进程 `TAKE()` 中,在访问共享变量 `amount` 的代码段前后分别执行 `P(mutex)` 和 `V(mutex)`,确保同一时刻只有一个进程进入临界区。

**【解析】** 假设存钱进程 `SAVE()` 和取钱进程 `TAKE()` 的正确逻辑为:

  • `SAVE()`:读取 `amount` 到局部变量,加 10,再写回 `amount`。
  • `TAKE()`:读取 `amount` 到局部变量,减 10,再写回 `amount`。 哥哥先存了两次钱,`amount` 从 0 增加到 20。第三次存钱时,弟弟同时取钱,两个进程并发执行,由于没有互斥保护,它们的操作可能交错执行,导致竞态条件。

考虑第三次存钱和取钱的交错情况:

  • 若存钱先完整执行,再取钱执行:存钱后 `amount=30`,取钱后 `amount=20`,最终为 20。
  • 若取钱先完整执行,再存钱执行:取钱后 `amount=10`,存钱后 `amount=20`,最终为 20。
  • 若操作交错:例如存钱读取 20 后,取钱也读取 20,然后存钱写入 30,取钱写入 10,最终为 10;或类似交错导致存钱写入覆盖取钱结果,最终为 30。 因此,`amount` 可能为 10、20 或 30。

为实现互斥,引入信号量 `mutex` 并初始化为 1。在 `SAVE()` 和 `TAKE()` 中,将访问 `amount` 的代码段作为临界区,在进入前执行 `P(mutex)`(申请资源),退出后执行 `V(mutex)`(释放资源)。这样,任何时刻只有一个进程能执行临界区代码,避免数据不一致。修改后的代码示例如下:

semaphore mutex = 1;

SAVE() {
    P(mutex);
    int m1 = amount;
    m1 = m1 + 10;
    amount = m1;
    V(mutex);
}

TAKE() {
    P(mutex);
    int m2 = amount;
    m2 = m2 - 10;
    amount = m2;
    V(mutex);
}
`

通过 P、V 操作确保进程互斥执行,保证 `amount` 操作的原子性。