线程进程区别

进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

进程 Process ,独占系统一部分资源,各自资源隔离。

  • 同主机进程间数据交互机制:无名管道(PIPE)、有名管道(FIFO)、消息队列(Message Queue)和共享内存(Shared Memory)。
  • 同主机进程间同步通信机制:信号量(Semaphore)。
  • 同主机进程间异步通信机制:信号(Signal)。
  • 不同主机间进程数据交互机制:套接字(Socket)、远程调用RPC(Remote Procedure Call)。

命名管道是实际存在的文件,而无名管道是在内存里的,使用前需要先打开,管道默认的read和write操作都是阻塞式的。

  • 无名管道主要用于具有亲缘关系的父子进程之间的通信,是临时性的,需要先创建管道,再创建子进程;
  • 管道都是单向的,若要实现双向通信,则需要两个管道。

缘进程与子进程通过无名通道通信

rd, wr = IO.pipe

if fork
 wr.close
 puts "Parent got: <#{rd.read}>"
 rd.close
 Process.wait
else
 rd.close
 puts "Sending message to parent"
 wr.write "Hi Dad"
 wr.close
end

亲缘子进程退出

puts "This is #{Process.pid}"
fork do
    puts "In child, pid = #{$$}"
    exit 99
end
pid = Process.wait
puts "Child terminated, pid = #{pid}, exit code = #{$? >> 8}"

线程与队列

require 'thread'

queue = Queue.new

producer = Thread.new do
  5.times do |i|
    sleep rand(i) # simulate expense
    queue << i
    puts "#{i} produced"
  end
end

consumer = Thread.new do
  5.times do |i|
    value = queue.pop
    sleep rand(i/2) # simulate expense
    puts "consumed #{value}"
  end
end

consumer.join

线程”睡”排序~

@threads, @r = [], []
arr = [2,4,5,6,1,3,9,8,7,0]
arr.each {|e|@threads << Thread.new {sleep e*0.1; @r << e} }
@threads.each {|t|t.join}
p @r

用线程实现timeout(摘自Timeout::timeout源码)

def timeout sec = nil
  return yield if sec == 0 or sec.nil?
  begin
    x = Thread.current
    y = Thread.start {
      begin
        sleep sec
      rescue => e
        x.raise e
      else
        x.raise "program execution expired"
      end
    }
    return yield
  ensure
    if y
      y.kill
      y.join # make sure y is dead.
    end
  end
end

线程安全

使用共享变量,部分线程没有执行完,就输出结果了,会导致线程不安全。

require 'thwait'

class MultipleThreadTest
  @n = 0

  def self.cal
    threads = 10000.times.map do
      Thread.start {
        @n += 1
      }
    end

    ThreadsWait.all_waits(*threads)
    @n
  end
end

p MultipleThreadTest.cal # 10000

附录