gpt4 book ai didi

ruby - 同步线程启动

转载 作者:太空宇宙 更新时间:2023-11-03 16:13:37 25 4
gpt4 key购买 nike

我正在运行一些代码(经过简化,但仍然破坏下面的版本),在等待第一次切换时执行失败约 1/3000。应该发生的是:

  • threads[0] 启动并获取互斥体
  • threads[0] 通知 cond_main 因此主线程可以创建 thread[1]
  • thread[1]/thread[0] 做一些工作等待彼此的信号

不幸的是,它在 thread[0] 中失败 - cond.wait 以超时结束并引发异常。我将如何同步它,确保 cond_main 不会过早收到信号?

理想情况下,我想从主线程传递一个锁定的互斥锁,并在第一个生成的线程中将其解锁,但 Ruby 要求在同一线程中解锁互斥锁 - 所以这行不通。

独立的复制器(本身没有多大意义,但真正的工作被剥离了):

def run_test
mutex = Mutex.new
cond = ConditionVariable.new
cond_main = ConditionVariable.new
threads = []

t1_done = false
t2_done = false

threads << Thread.new do
mutex.synchronize do
# this needs to happen first
cond_main.signal
cond.wait(mutex, 2)
raise 'timeout waiting for switch' if !t2_done

# some work
t1_done = true
cond.signal
end
end
cond_main.wait(Mutex.new.lock, 2)

threads << Thread.new do
mutex.synchronize do
cond.signal
# some work
t2_done = true
cond.wait(mutex, 2)
raise 'timeout waiting for switch' if !t1_done
end
end

threads.map(&:join)
end

5000.times { |x|
puts "Run #{x}"
run_test
}

在 Ruby 2.5.3 上测试

最佳答案

设置一个 while block 以在第二个线程完成时停止等待(参见更多 here ):

def run_test
mutex = Mutex.new
cond = ConditionVariable.new
cond_main = ConditionVariable.new
threads = []

spawned = false

t1_done = false
t2_done = false

threads << Thread.new do
mutex.synchronize do
while(!spawned) do
cond.wait(mutex, 2)
end
raise 'timeout waiting for switch' if !t2_done

# some work
t1_done = true
cond.signal
end
end

threads << Thread.new do
mutex.synchronize do
spawned = true
cond.signal
# some work
t2_done = true
cond.wait(mutex, 2)
raise 'timeout waiting for switch' if !t1_done
end
end

threads.map(&:join)
end

50000.times { |x|
puts x
run_test
}

或者,使用 counting semaphore ,我们可以为线程分配一些优先级:

require 'concurrent-ruby'

def run_test
mutex = Mutex.new
sync = Concurrent::Semaphore.new(0)
cond = ConditionVariable.new
cond_main = ConditionVariable.new
threads = []

t1_done = false
t2_done = false

threads << Thread.new do
mutex.synchronize do
sync.release(1)
# this needs to happen first
cond.wait(mutex, 2)
raise 'timeout waiting for switch' if !t2_done

# some work
t1_done = true
cond.signal
end
end

threads << Thread.new do
sync.acquire(1)
mutex.synchronize do
cond.signal
# some work
t2_done = true
cond.wait(mutex, 2)
raise 'timeout waiting for switch' if !t1_done
end
end

threads.map(&:join)
end

50000.times { |x|
puts x
run_test
}

我更喜欢第二种解决方案,因为它允许您控制线程的顺序,尽管感觉有点脏。

奇怪的是,在 Ruby 2.6 上,您的代码似乎没有引发异常(测试超过 1000 万次运行)。

关于ruby - 同步线程启动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53974673/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com