在用户级别C中实现信号量

时间:2015-10-27 06:39:02

标签: c operating-system semaphore atomic locks

信号量的有效和必要的实现要求它是原子指令。

我在互联网上看到几个使用变量(如count)或数据结构(如queue)实现信号量的用户级C实现。但是,涉及变量donot的指令作为原子指令运行。那么如何在用户级别C中实现sempahore呢。

c库semaphore.h如何实现信号量?

3 个答案:

答案 0 :(得分:3)

几乎可以肯定答案是#34;它没有" - 相反,它将调用提供必要原子操作的内核服务。

答案 1 :(得分:2)

之前标准 C中不可能。正如您所说,您需要的是原子操作。 最后指定了它们,例如参见stdatomic.h

如果您使用的是旧版标准,则必须直接使用嵌入式汇编程序或依赖编译器的特定于供应商的扩展,例如参见GCC atomic builtins。当然,处理器支持内存屏障指令,检查和交换操作等。它们只能从纯及更早版本访问,因为并行执行不在标准范围内

在阅读MartinJames的评论之后,我应该在此处添加说明:这仅适用于您在用户空间中实现所有线程,因为信号量必须阻止等待它的线程,因此如果线程由内核的调度程序管理(因为例如,在Linux上运行pthreads的情况下,有必要进行系统调用。不在您的问题范围内,但原子操作可能仍然对于实现例如无锁数据结构。

答案 2 :(得分:0)

您可以实现信号量操作,就像:

一样简单
void sema_post(atomic_uint *value) {
    unsigned old = 0;
    while (!atomic_compare_exchange_weak(value, &old, old + 1));
}

void sema_wait(atomic_uint *value) {
    unsigned old = 1;
    while (old == 0 || !atomic_compare_exchange_weak(value, &old, old - 1));
}

语义上可以,但它在sema_wait中忙着等待(旋转)。 (请注意,sema_post是无锁的,但它也可以旋转。)相反,它应该睡眠,直到value变为正数。使用原子无法解决此问题,因为所有原子操作都是非阻塞的。在这里,您需要OS内核的帮助。因此,有效的信号量可以使用基于原子的类似算法,但在两种情况下进入内核(有关此方法的更多详细信息,请参阅Linux futex ):

  • sema_wait:当找到value == 0时,请求睡觉
  • sema_post:当它从{0}增加value时,要求唤醒另一个睡眠线程(如果有的话)

通常,要在数据结构上实现无锁(使用原子)操作,它要求每个操作都适用于任何状态。对于信号量,等待不适用于值0.