在OS X上使用sem_init

66

我正在处理一些使用pthread和semaphore库的代码。在我的Ubuntu机器上,sem_init函数工作正常,但是在OS X上,sem_init函数完全没有效果。这个库有问题吗?还是有其他方法可以实现?以下是我用来测试的代码。

sem_t sem1;
sem_t sem2;
sem_t sem3;
sem_t sem4;
sem_t sem5;
sem_t sem6;

sem_init(&sem1, 1, 1);
sem_init(&sem2, 1, 2);
sem_init(&sem3, 1, 3);
sem_init(&sem4, 1, 4);
sem_init(&sem5, 1, 5);
sem_init(&sem6, 1, 6);

这些值看起来像是随机数,并且在 sem_init 调用后不会改变。


4
应该测试sem_init的返回值。 - bfontaine
1
请注意,在Mac OS X Yosemite(10.10)中,sem_init()sem_destroy()sem_getvalue()至少被标记为“已弃用”,因此会生成编译器警告。 - Jonathan Leffler
@JonathanLeffler 哦,不好意思。它不能在Mac OS X Yosemite(10.10.1)中工作。 - vipygd
另请参阅https://stackoverflow.com/questions/1413785/sem-init-on-os-x和https://stackoverflow.com/questions/641126/posix-semaphores-on-mac-os-x-sem-timedwait-alternative您的选择是使用GCD信号量、mach信号量、互斥锁+pthread条件变量或互斥锁+管道(根据需要阻塞和发出信号)重新实现所需的API。 - undefined
3个回答

102

不支持未命名的信号量,需要使用命名信号量。

要使用命名信号量而非未命名信号量,请使用sem_open替代sem_init,并使用sem_closesem_unlink替代sem_destroy


51
哇。<semaphore.h> 声明了 sem_init 函数,以便在 OS X 上可以正确编译,但它返回 -1 并将 errno 设置为 ENOSYS(未实现的函数)。 - Adam Rosenfield
好的,现在我正在寻找一个使用C++ Boost库的信号量的好例子。我听说这是一个强大的实现。 - jcpennypincher
sem_getvalue() 也不起作用......请参见https://dev59.com/1HLYa4cB1Zd3GeqPWVSY#16655541 - user454322

26
这些天在OS X上比命名信号量更好的解决方案是Grand Central Dispatch的dispatch_semaphore_t。它的工作方式非常类似于未命名的POSIX信号量。
初始化信号量:
#include <dispatch/dispatch.h>
dispatch_semaphore_t semaphore;
semaphore = dispatch_semaphore_create(1); // init with value of 1

等待并发布(信号):

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
...
dispatch_semaphore_signal(semaphore);

摧毁:

dispatch_release(semaphore);

这个头文件已经有很好的文档说明,我觉得使用起来非常容易。


GCD信号量是GCD级别的功能。理论上,如果与pthread级别结合使用,可能会导致一些问题。 - eonil
2
@MichaelDorst 错误的问题。基本上,除非它们明确设计为一起工作,否则您不应使用在不同抽象层面上公开的API来控制另一个抽象层面。即使您知道所有细节并且它们现在正在工作,因为实现细节以后可能会发生变化。如果您没有互操作性的证据,您应该将这种用法视为不安全,因为存在潜在问题。而且没有证据表明GCD API将按预期工作于POSIX线程。 - eonil
@MichaelDorst 正确的问题应该是“GCD API在POSIX线程中能否工作的证据是什么?”没有证据意味着不安全。 - eonil
@MichaelDorst GCD 不是一个“扩展”或“实用程序”功能来帮助 pthread。它是一个独立的和不透明的抽象,不依赖于实现细节。 - eonil
@MichaelDorst 请记住,一个线程可以运行多个GCD队列,而一个GCD队列可以在除主队列以外的任何线程上运行。停止GCD队列并不能保证停止POSIX线程。使用GCD API来控制POSIX线程只是一种无意义的做法。 - eonil
显示剩余3条评论

0
如果您查看源代码中 sem_init 的实现,则只会返回一个错误,而一些其他的 bsd 函数如 sem_open 仍然有实现。
“已弃用”的 posix 函数和 libdispatch/GCD 都使用诸如 semphore_create 和 semaphore_wait 的用户空间调用。如果您想要始终使用内核/操作系统的旧式信号量,可以直接使用这些。但是最好使用像 GCD 中那样在内部使用原子计数器的信号量,并仅在必须等待时才调用内核/操作系统。

https://github.com/apple/darwin-xnu/blob/a1babec6b135d1f35b2590a1990af3c5c5393479/bsd/kern/posix_sem.c


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接