Ruby 线程基本原理
- 轻量级执行单元:Ruby 线程是一种轻量级的执行单元,允许在同一进程内并发执行多个任务。它们共享进程的内存空间,包括全局变量和堆内存等。
- 协作式调度:Ruby 使用协作式调度(Cooperative Scheduling),也称为用户级线程调度。这意味着线程不会被操作系统抢占式地调度,而是在执行过程中主动让出 CPU 控制权,例如通过调用
Thread.pass
方法或执行一些 I/O 操作(如文件读取、网络请求)时,会暂停当前线程,允许其他线程运行。
避免多线程资源竞争问题的方法
- 互斥锁(Mutex)
- 原理:互斥锁是一种简单的同步机制,它只允许一个线程在同一时间进入临界区(共享资源访问代码段)。
- 使用示例:
mutex = Mutex.new
shared_resource = 0
thread1 = Thread.new do
mutex.lock
shared_resource += 1
mutex.unlock
end
thread2 = Thread.new do
mutex.lock
shared_resource += 1
mutex.unlock
end
thread1.join
thread2.join
puts shared_resource # 输出 2,避免了资源竞争导致的错误结果
- 读写锁(ReadWriteLock)
- 原理:读写锁允许同时有多个线程进行读操作,但只允许一个线程进行写操作。读操作之间不会产生资源竞争,因此可以并发执行,提高效率。
- 使用示例:
require 'thread'
rw_lock = ReadWriteLock.new
shared_data = []
reader1 = Thread.new do
rw_lock.synchronize(:read) do
# 读取 shared_data
end
end
writer1 = Thread.new do
rw_lock.synchronize(:write) do
# 修改 shared_data
end
end
reader1.join
writer1.join
- 条件变量(ConditionVariable)
- 原理:条件变量用于线程间的同步通信,它允许线程在满足某个条件时被唤醒。通常与互斥锁一起使用,线程在等待条件变量时会释放持有的互斥锁,避免死锁。
- 使用示例:
mutex = Mutex.new
cv = ConditionVariable.new
ready = false
producer = Thread.new do
mutex.lock
# 生产数据
ready = true
cv.signal
mutex.unlock
end
consumer = Thread.new do
mutex.lock
cv.wait(mutex) until ready
# 消费数据
mutex.unlock
end
producer.join
consumer.join
- 线程局部存储(Thread Local Storage)
- 原理:每个线程都有自己独立的存储空间,不同线程之间不会共享这些数据,从而避免了资源竞争。
- 使用示例:
thread_local_var = Thread.current.thread_variable_get(:my_var) rescue nil
if thread_local_var.nil?
thread_local_var = []
Thread.current.thread_variable_set(:my_var, thread_local_var)
end
# 每个线程独立操作自己的 thread_local_var,无资源竞争问题