我正在用Ruby实现“Fair Barbershop”问题。这是一个类赋值,但我不是在寻找任何讲义。我已经疯狂地搜索了,但我似乎找不到一个Ruby实现的信号量镜像在C中找到的那些。
我知道有互斥锁,这很好,单实现,做的正是这种信号量应该做的。
然后是条件变量,我原以为这样做会很好,但看看这些,它们需要一个互斥体来处理每个等待调用,这在我看来就像我不能给信号量输入数值一样(比如,我有7个理发店,3个理发师,等等)。
我想我需要一个计数信号量,但是我觉得Ruby在它的核心中没有包含这样一个类(从我所能找到的来看)有点奇怪。有人能帮我指出正确的方向吗?
7条答案
按热度按时间z2acfund1#
如果您使用的是JRuby,则可以从Java导入信号量,如this article所示。
bt1cpqcv2#
Ruby非常适合消除SysV信号量的API缺陷,而SysV信号量是最好的--它们是进程间信号量,您可以使用SEM_UNDO,这样即使SIGKILLs也不会扰乱全局状态(POSIX进程间信号量没有这个功能),使用SysV信号量,您可以同时对多个信号量执行原子操作,只要它们在同一个信号量集中。
至于线程间信号量,它们应该可以用条件变量和互斥体完全模拟(参见BernanrdoMartinez的链接了解如何模拟)。
kpbwa7wx3#
我还发现了这个代码:https://gist.github.com/pettyjamesm/3746457
也许有人会喜欢这个选择。
blmhpbnm4#
由于concurrent-ruby是稳定的(超过1.0)并且被广泛使用,因此最好的(并且可跨Ruby实现移植)解决方案是使用它的
Concurrent::Semaphore
类m3eecexj5#
感谢@x3ro提供的链接。它为我指明了正确的方向。然而,随着Fukumoto提供的实现(至少对于rb1.9.2)Thread.critical不可用。此外,我尝试用Thread.exclusive{}替换Thread.critical调用,结果导致了死锁。(我已经在下面链接了),它通过用互斥体::synchronize{}替换Thread.exclusive{}以及其他一些调整解决了这个问题。感谢@x3ro把我推向了正确的方向。
http://redmine.ruby-lang.org/attachments/1109/final-semaphore.patch
yqyhoc1h6#
由于这里的其他链接对我来说不起作用,我决定快速地组合一些东西。我还没有测试过这个,所以欢迎输入和修改。它简单地基于这样的想法:互斥锁是一个二进制信号量,因此信号量是一组互斥锁。
https://gist.github.com/3439373
jxct1oxe7#
我认为,在此上下文中提到
Thread::Queue
可能会对其他遇到此问题的人有所帮助。Queue
是一个线程安全的工具(使用一些后台同步原语实现),可以像传统的多处理信号量一样使用,只需要一点想象力,并且它默认是预加载的,至少在ruby v3中是这样:可以很简单地证明:
docs for ruby v3.1表示可以使用
enumerable
对象初始化Queue
以设置初始内容,但在我的v3.0中没有此功能。但是,如果您想要一个具有7个许可证信号量,则很容易使用以下内容填充框:我使用
Queue
来实现一些工作线程之间的接力棒传递:因此,线程task_master可以执行步骤one和three,线程little_helper在适当的时间介入以处理步骤two:
注意,
WaitForBaton
类的.pass_baton
方法中的sleep 0.0
是防止task_master将接力棒传递给自身所必需的:除非线程调度 * 碰巧 * 在baton.pass_baton
之后立即从task_master跳离,否则接下来发生的事情是task_master的baton.wait_for_baton
-它再次将接力棒收回。sleep 0.0
明确地将执行让给可能正在等待运行的任何其他线程(并且,在这种情况下,阻塞在底层Queue
上)。放弃执行不是默认行为,因为这是信号量技术的一种有点不寻常的用法--想象一下,task_master可以生成许多任务供little_helper执行,并且task_master可以在通过
Thread::Queue
的.push([object])
方法传递任务之后立即高效地返回到生成任务。