【问题标题】:Semop: When decreasing a set of semaphores are all decremented at once or does it block on first failure?Semop:当减少一组信号量时会立即减少还是在第一次失败时阻塞?
【发布时间】:2012-04-18 09:23:33
【问题描述】:

所以,如果我有一个 信号量集 semidnum_of_sems 信号量和一个 sembuf *deleter_searchers_down

struct sembuf *deleter_searchers_down 
                        = malloc(sizeof (*deleter_searchers_down) * num_of_sems);
for (i = 0; i < num_of_sems; ++i) {
            (deleter_searchers_down + i)->sem_op = -1;
            (deleter_searchers_down + i)->sem_num = i;
            (deleter_searchers_down + i)->sem_flg = SEM_UNDO;
        }
semop(semid, deleter_searchers_down, num_of_sems);

对 semop 的调用将尝试一次降低集合中的所有信号量,或者一旦它尝试降低第一个为 0 的信号量并在其他进程提升该特定信号量后继续执行,它会阻塞吗?

【问题讨论】:

  • 好吧,信号量完全按照你说的做,也就是说,当它们降低时,如果它们为 0,它们会阻塞进程。
  • 请仔细阅读问题 - semop 会尝试降低所有集合并阻止所有零值,还是会在第一个(第一个?)遇到 0 时阻止
  • 您可以指定 IPC_NOWAIT 在失败时立即返回。见:pubs.opengroup.org/onlinepubs/7908799/xsh/semop.html
  • @RedX 链接是相关的,IPC_NOWAIT 不是。问题是是否立即执行数组中不会导致阻塞的操作之一,或者它是否被延迟并且在进程解除阻塞时一次完成所有操作(导致数组中的后续操作之一导致它首先阻止)

标签: c unix semaphore


【解决方案1】:

在所有更新可以作为一个单元进行之前,不会发生更新。

POSIX 规范可能更清楚地说明这一点,尽管它确实说 semop 是原子的。

在 Linux 上,glibc 中的semop(3)semop(2) 的简单包装器。 semop(2) 手册页反过来说

sops 中包含的一组操作以数组顺序原子地执行,也就是说,这些操作要么作为一个完整的单元执行,要么不作为一个完整的单元执行完全没有。

HP-UX semop(2) 联机帮助页更加清晰:

信号量 数组操作是原子的,因为没有任何信号量操作 一直执行到所有信号量的阻塞条件 该数组已被删除。

【讨论】:

  • 谢谢 - 这是否意味着尝试关闭 semid 的进程将阻塞第一个数组元素 0 并且 semop() 将撤消所有先前的数组元素 downs() ?
  • 这取决于实现。例如,Linux ipc/sem.c(函数try_atomic_semop)中的代码与您描述的类似。它会尝试这些操作,如果其中任何一个阻塞,则撤消更改。但是有一点很重要:更新是在持有信号量集的锁的同时完成的。因此,任何其他任务都看不到不一致的状态:希望更改信号量的任务首先必须获得锁,而在信号量上阻塞的任务已经处于休眠状态。所以最终操作是真正的原子操作。
  • 好的 - 谢谢 - 最后一点:调用 semop 的进程不可能(实现)阻塞 所有 0 的信号量?
  • 我不确定我是否正确理解了这个问题,所以请随时纠正我。如果多个信号量为 0 且无法获取,则对 semop 的调用将阻塞,直到这成为可能。 semop 在整个操作完成之前不会返回。如果您的问题是关于浪费 CPU 时间,在最近的 Linux 内核中,该任务在信号量等待队列上时是不可调度的:一旦另一个任务调用 semop 并更改信号量集,它就会休眠并被唤醒。
  • 我的意思是如果调用 semop 的进程(如给出的示例中)可以阻塞 all 为 0 的信号量 - 不仅在第一个 (按数组顺序)它遇到的是 0。所以 而不是 撤消操作以阻止所有为 0 的操作并等待所有这些操作 - 但是当所有操作都可用时,不要重做,而只是返回。但这会与信号量的作用相矛盾(如果有其他进程在 semid 中对 sem 进行升级,则很容易想到一个反例)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-30
  • 2014-07-03
  • 1970-01-01
  • 1970-01-01
  • 2021-04-05
  • 2018-04-28
  • 2015-07-06
相关资源
最近更新 更多