Discourse 中用 Redis 实现互斥锁有这么一段:
if current_expire_time && now <= current_expire_time.to_i
  redis.unwatch
  got_lock = false
else
  result =
    redis.multi do
      redis.set key, expire_time.to_s
      redis.expire key, validity
    end
  got_lock = !result.nil?
end
当 A 线程还在执行代码时(但是已经超过超时时间),B 线程发现锁已经超过超时时间,然后 B 设置了新的超时时间并获取了锁(仅仅在 A 线程执行完毕后在 log 中记录一条 warning),这种做法是否合理? 感觉上即使一个线程的执行时间如果超过了超时时间,其他线程也不应该获取到这个锁,而是获取锁失败。
另外,也是在 distributed_mutex.rb:
# NOTE wrapped in mutex to maintain its semantics
def synchronize
  @mutex.synchronize do
    expire_time = get_lock
    begin
      yield
    ensure
      current_time = redis.time[0]
      if current_time > expire_time
        warn("held for too long, expected max: #{@validity} secs, took an extra #{current_time - expire_time} secs")
      end
      if !unlock(expire_time) && current_time <= expire_time
        warn("the redis key appears to have been tampered with before expiration")
      end
    end
  end
end
这里注释说使用 @mutex(Mutex.new)来保持互斥,是为了在下面这种情况下保持互斥吗?
mutex = DistributedMutex.new("foo_key", foo_redis)
10.times do
  Thread.new do
    mutex.synchronize do
      # some code
    end
  end
end
但是在 Discourse 中的使用方式都是下面这样,所以有点迷惑,这种方式使用的话是不是就不需要 Mutex.new.synchronize 来保证互斥语义了:
DistributedMutex.synchronize("model_#{id}") do
  # some code
end
附:Rails 中,关于多线程方面的知识可以在哪里接触到?是一个或 n 个请求就会对应一个线程,又或者是一个 session 会对应一个线程?