Ruby线程(二)

      熟悉线程的朋友应该对经典的售票员卖票程序不陌生。全国各地有很多售票点同时发售车票,车票在这里作为一个公用的资源,各地的售票中心访问资源,打印车票给顾客。我们来看一下ruby实现这个简单功能的代码吧:

# 线程-买票实例
class Ticket
  attr_reader :ticket
  attr_reader :value
  def initialize
    @ticket = %w(a b c d e f g h i j k l m n o p q r s t u v w x y z)
    @value = 0
  end

  def buy_ticket
    @k = @ticket
    if @k.empty?
      puts "no result"
      @value +=1
    else
      sleep(3*rand)
      puts "the ticket is #{@k.last} "
      sleep(3*rand)
      @value +=1
      puts "OK #{@value}"
      @ticket.pop
      puts "**************分隔符******************"
    end
  end
end


a = Ticket.new
t1 = Thread.new { 10.times {puts "线程1" ; a.buy_ticket  } }
t2 = Thread.new { 10.times { puts "线程2"; a.buy_ticket  } }
t3 = Thread.new { 10.times { puts "线程3"; a.buy_ticket  } }
t1.join
t2.join
t3.join

      我们开了3个线程分别表示不同的3个售票点同事发售车票,我们在发售车票的时候使用了sleep来模拟工作人员操作的时间。

 @ticket = %w(a b c d e f g h i j k l m n o p q r s t u v w x y z)

      @ticket这个数组用来表示一组车票。好我们来运行这个程序,看能看到什么结果

线程1线程2线程3





the ticket is z 

OK 1

**************分隔符******************

线程3

the ticket is y 

the ticket is y 

the ticket is y 

OK 2

**************分隔符******************

线程2

OK 3

**************分隔符******************

线程1

OK 4

**************分隔符******************

线程3

the ticket is v 

the ticket is v 

the ticket is v 

OK 5

      我们可以看见,有的车票被多个窗口同时卖出,当然这在规定当中是不允许的。这个是为什么呢?我们来看一下程序。乍一看是肯定没有什么问题的。细细想想,假设我们的线程1进入卖票程序,并查看到当前可以买y票。线程1睡眠一段时间,假设这段时间正好线程2进来了,并执行了卖票程序,此时线程1并未实际意义上的把票卖了出去,这就导致了两个线程卖出了同一张票。

       那么有没有解决办法呢?比如说,在线程1进入程序的时候,就把票给锁死了,这样线程2来的时候就不能对该张票进行操作。在ruby当中有个监视器monitor可是实现该功能。我们对买票这个操作进行监视控制,只能同时一个人来操作。好吧,我们来看一下下面的代码:

# 线程-买票实例
require 'monitor'
class Ticket
  attr_reader :ticket
  attr_reader :value
  def initialize
    @ticket = %w(a b c d e f g h i j k l m n o p q r s t u v w x y z)
    @value = 0
  end

  def buy_ticket
    @k = @ticket
    if @k.empty?
      puts "no result"
      @value +=1
    else
      sleep(3*rand)
      puts "the ticket is #{@k.last} "
      sleep(3*rand)
      @value +=1
      puts "OK #{@value}"
      @ticket.pop
      puts "**************分隔符******************"
    end
  end
end


a = Ticket.new
k = Monitor.new
t1 = Thread.new { 10.times {k.synchronize{puts "线程1" ; a.buy_ticket  }} }
t2 = Thread.new { 10.times {k.synchronize{puts "线程2" ; a.buy_ticket  }} }
t3 = Thread.new { 10.times {k.synchronize{puts "线程3" ; a.buy_ticket  }} }
t1.join
t2.join
t3.join

puts a.value

      我们使用了监视器来对资源进行监视,不能同时由多个线程进行操作,避免重复卖票的情况,这中间的核心部分就是如下所示:

 

k = Monitor.new
t1 = Thread.new { 10.times {k.synchronize{puts "线程1" ; a.buy_ticket  }} }
t2 = Thread.new { 10.times {k.synchronize{puts "线程2" ; a.buy_ticket  }} }
t3 = Thread.new { 10.times {k.synchronize{puts "线程3" ; a.buy_ticket  }} }

     当然,我们可以不对该操作进行监视,我们对票据资源进行监视。也会使用到synchronize。这里就不再赘述,想知道的可以参考programming ruby。

     好拉。今天就写这么多吧。o(∩_∩)o...哈哈

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值