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
完整代码 distributed_mutex.rb
当 A 线程还在执行代码时(但是已经超过超时时间),B 线程发现锁已经超过超时时间,然后 B 设置了新的超时时间并获取了锁(仅仅在 A 线程执行完毕后在 log 中记录一条 warning),这种做法是否合理? 感觉上即使一个线程的执行时间如果超过了超时时间,其他线程也不应该获取到这个锁,而是获取锁失败。 A线程要负责释放锁,否则如果A异常退出那么就是死锁了。如果A在锁过期时间内执行不完,A可以extend锁。
但是在 Discourse 中的使用方式都是下面这样,所以有点迷惑,这种方式使用的话是不是就不需要 Mutex.new.synchronize 来保证原子性了: DistributedMutex.synchronize借助redis实现了跨进程/机器的锁,Mutex#synchronize实现了本进程起的线程级别的锁。的确可以只用redis实现线程级别的锁,但是毕竟有额外的redis读写操作,不如直接用内置的Mutex#synchronize。
附:Rails 中,关于多线程方面的知识可以在哪里接触到?是一个或 n 个请求就会对应一个线程,又或者是一个 session 会对应一个线程? Rails用的多线程知识可能并不多,顶多是如何在多线程环境下初始化一个单例。多线程可以看puma或者sidekiq。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。