Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 互斥锁不工作,使用队列工作。为什么?_Ruby_Concurrency_Synchronization_Mutex - Fatal编程技术网

Ruby 互斥锁不工作,使用队列工作。为什么?

Ruby 互斥锁不工作,使用队列工作。为什么?,ruby,concurrency,synchronization,mutex,Ruby,Concurrency,Synchronization,Mutex,在本例中,我希望同步两个put,以使输出为abababab…,在输出上没有任何双as或bs 我有三个例子:使用队列、在内存中使用互斥体以及在文件中使用互斥体。队列示例可以很好地工作,但互斥体不行 我不是在寻找工作代码。我想了解为什么使用队列是有效的,而使用互斥是无效的。根据我的理解,它们应该是等价的。 队列示例:工作 def a Thread.new do $queue.pop puts "a" b end end def b Thread.new do

在本例中,我希望同步两个
put
,以使输出为
abababab…
,在输出上没有任何双
a
s或
b
s

我有三个例子:使用队列、在内存中使用互斥体以及在文件中使用互斥体。队列示例可以很好地工作,但互斥体不行

我不是在寻找工作代码。我想了解为什么使用队列是有效的,而使用互斥是无效的。根据我的理解,它们应该是等价的。

队列示例:工作

def a
  Thread.new do
    $queue.pop
    puts "a"
    b
  end
end

def b
   Thread.new do
    sleep(rand)
    puts "b"
    $queue << true
  end
end

$queue = Queue.new
$queue << true
loop{a; sleep(rand)}
互斥变量示例:不工作

def a
  Thread.new do
    $mutex.flock(File::LOCK_EX)
    puts "a"
    b
  end
end

def b
   Thread.new do
    sleep(rand)
    puts "b"
    $mutex.flock(File::LOCK_UN)
  end
end

MUTEX_FILE_PATH = '/tmp/mutex'
File.open(MUTEX_FILE_PATH, "w") unless File.exists?(MUTEX_FILE_PATH)
$mutex = File.new(MUTEX_FILE_PATH,"r+")
loop{a; sleep(rand)}
def a
  Thread.new do
    $mutex.lock
    puts "a"
    b
  end
end

def b
   Thread.new do
    sleep(rand)
    puts "b"
    $mutex.unlock
  end
end

$mutex = Mutex.new
loop{a; sleep(rand)}

在互斥锁示例中,在方法
b
中创建的线程会休眠一段时间,打印
b
,然后尝试解锁互斥锁。这是不合法的,线程无法解锁互斥锁,除非它已经持有该锁,如果您尝试以下操作,则会引发ThreadError:

m = Mutex.new
m.unlock
结果:

release.rb:2:in'unlock':尝试解锁未锁定的互斥锁(ThreadError)
从release.rb:2:in`'
在您的示例中不会看到这一点,因为。您可以使用–如果您添加

Thread.abort_on_exception = true
在文件的顶部,您将看到如下内容:

a
B
with mutex.rb:15:“解锁”中:尝试解锁未锁定的互斥锁(ThreadError)
使用互斥锁从。rb:15:in'block in b'
(您可能会看到多个
a
,但只有一个
b

a
方法中,创建获取锁的线程,打印
a
,调用另一个方法(创建新线程并立即返回),然后终止。它似乎没有很好的文档记录,但当一个线程终止时,它会释放它拥有的所有锁,因此在这种情况下,锁几乎立即被释放,允许其他
a
线程运行

总的来说,锁的作用不大。它根本不阻止
b
线程运行,虽然它确实阻止两个
a
线程同时运行,但一旦持有它的线程退出,它就会被释放

我想你可能在想,而Ruby医生说他们在想

Ruby在标准库中不提供信号量,但它确实提供了。(该链接指向较旧的2.0.0文档。Ruby 2.1+默认需要
线程
标准库,而这一移动似乎导致当前文档不可用。还要注意,Ruby还有一个单独的库(我认为)添加了相同的功能(互斥体和条件变量)以更面向对象的方式。)

使用条件变量和互斥量可以控制线程之间的协调。显示了一种可能的方法(尽管我认为他的解决方案的启动方式存在竞争条件)


如果您查看(这也是到2.0.0的链接,线程库在最新版本中已转换为C,Ruby版本更容易理解),您可以看到它是通过和实现的。当您在队列示例中的
a
线程中调用
$queue.pop
时,您最终的调用方式与Uri Agassi在其方法
a
中的应答调用
$cv.wait($mutex)
相同。类似地,当您呼叫
$queue简短回答时
您对互斥的使用不正确。使用
队列
,您可以先用一个线程填充,然后用另一个线程填充
弹出
,但不能用一个线程锁定
互斥锁
,然后用另一个线程解锁

正如@matt所解释的,有一些微妙的事情正在发生,比如互斥锁自动解锁和你看不到的无声异常

互斥体的常用方式
互斥体用于访问特定的共享资源,如变量或文件。因此,变量和文件的同步允许同步多个线程。互斥锁本身并不真正同步线程

例如:

  • thread\u a
    thread\u b
    可以通过共享布尔变量(如
    true\u a\u false\u b
    进行同步
  • 每次使用该布尔变量时,您都必须访问、测试和切换该布尔变量,这是一个多步骤的过程
  • 必须确保此多步骤过程以原子方式进行,即不中断。此时您将使用互斥锁。下面是一个简单的例子:

  • 基于文件的版本的问题尚未正确解决。 它不起作用的原因是
    f.flock(File::LOCK_EX)
    在对同一文件
    f
    多次调用时不会阻塞。 这可以通过以下简单的顺序程序进行检查:

    require 'thread'
    
    MUTEX_FILE_PATH = '/tmp/mutex'
    $fone= File.new( MUTEX_FILE_PATH, "w")
    $ftwo= File.open( MUTEX_FILE_PATH)
    
    puts "start"
    $fone.flock( File::LOCK_EX)
    puts "locked"
    $fone.flock( File::LOCK_EX)
    puts "so what"
    $ftwo.flock( File::LOCK_EX)
    puts "dontcare"
    
    它可以打印除dontcare之外的所有内容

    因此,基于文件的程序无法工作,因为

    $mutex.flock(File::LOCK_EX)
    

    从不阻拦。

    @sawa看看这个问题哦,我没有得到赏金?很高兴能帮上忙,但我没有这个。为什么我要释放
    b
    上的锁?由于
    b
    总是由
    a
    调用,我不能只锁定
    a
    的入口,并在调用
    put b
    后解锁吗?
    a
    创建多个线程。但是由于
    $mutex
    是一个全局变量,因此无论
    b
    是否解锁,由
    a
    创建的线程都不会锁定。
    $mutex.flock(File::LOCK_EX)