Latest web development tutorials

Ruby Multithreading

Each program running on the system is a process. Each process contains one or more threads.

A thread is a single sequential program control flow, simultaneously run multiple threads in a single program do different things, called multi-threading.

Ruby, we can be created by multiple threads Thread class, Ruby threads are a lightweight, it can be an efficient way to implement parallel code.


Creating a Ruby thread

To start a new thread, you can just call Thread.new:

# 线程 #1 代码部分
Thread.new {
  # 线程 #2 执行代码
}
# 线程 #1 执行代码

Examples

The following example shows how to use multithreading in Ruby program:

#!/usr/bin/ruby

def func1
   i=0
   while i<=2
      puts "func1 at: #{Time.now}"
      sleep(2)
      i=i+1
   end
end

def func2
   j=0
   while j<=2
      puts "func2 at: #{Time.now}"
      sleep(1)
      j=j+1
   end
end

puts "Started At #{Time.now}"
t1=Thread.new{func1()}
t2=Thread.new{func2()}
t1.join
t2.join
puts "End at #{Time.now}"

The above code is executed as a result of:

Started At Wed May 14 08:21:54 -0700 2014
func1 at: Wed May 14 08:21:54 -0700 2014
func2 at: Wed May 14 08:21:54 -0700 2014
func2 at: Wed May 14 08:21:55 -0700 2014
func1 at: Wed May 14 08:21:56 -0700 2014
func2 at: Wed May 14 08:21:56 -0700 2014
func1 at: Wed May 14 08:21:58 -0700 2014
End at Wed May 14 08:22:00 -0700 2014

Thread Life Cycle

1, create a thread can use Thread.new, you can also use the same syntax Thread.start or Thread.fork three ways to create a thread.

2, create a thread without starting, the thread will be executed automatically.

3, Thread class defines methods to manipulate thread. Thread of execution Thread.new code blocks.

4, the thread block is the value of the last statement in the thread, the thread can be invoked by a method, if the thread is finished, it returns the value of the thread, or does not return a value until the thread is finished.

5, Thread.current method returns an object for the current thread representation. Thread.main method returns the main thread.

6, the method is performed by Thread.Join threads, this method will suspend the main thread until the current thread is finished.


Thread State

Thread has five states:

Thread State return value
Executable run
Sleeping Sleeping
drop out aborting
Normal termination false
Abnormal termination occurs nil

Threads and aberrant

When a thread exception occurs, and no rescue was captured, the thread would normally be terminated without warning. However, if other threads Thread # join because the relationship has been waiting for this thread, then the waiting threads will also be raised the same exception.

begin
  t = Thread.new do
    Thread.pass    # 主线程确实在等join
    raise "unhandled exception"
  end
  t.join
rescue
  p $!  # => "unhandled exception"
end

Use the following three methods, you can get the interpreter to interrupt the operation when a thread terminates due to an exception.

  • Startup script specifies-d option, and debugging mode operation.
  • With Thread.abort_on_exception set the flag.
  • Use Thread#abort_on_exception specified thread set flag.

When using one of three methods described above, the entire interpreter will be interrupted.

t = Thread.new { ... }
t.abort_on_exception = true

Thread Synchronization

In Ruby, provides three synchronized manner, namely:

1. Mutex class implements Thread Synchronization

2. Regulatory data transfer Queue class implement thread synchronization

3. Use ConditionVariable synchronization control

By Mutex class implements Thread Synchronization

By Mutex class implements the thread synchronization control, if you also need a program variable clock in multiple threads, you can use the lock to lock the variable part. Code is as follows:

#!/usr/bin/ruby

require "thread"
puts "Synchronize Thread"

@num=200
@mutex=Mutex.new

def buyTicket(num)
     @mutex.lock
          if @num>=num
               @num=@num-num
               puts "you have successfully bought #{num} tickets"
          else
               puts "sorry,no enough tickets"
          end
     @mutex.unlock
end

ticket1=Thread.new 10 do
     10.times do |value|
     ticketNum=15
     buyTicket(ticketNum)
     sleep 0.01
     end
end

ticket2=Thread.new 10 do
     10.times do |value|
     ticketNum=20
     buyTicket(ticketNum)
     sleep 0.01
     end
end

sleep 1
ticket1.join
ticket2.join

The above code is executed as a result of:

Synchronize Thread
you have successfully bought 15 tickets
you have successfully bought 20 tickets
you have successfully bought 15 tickets
you have successfully bought 20 tickets
you have successfully bought 15 tickets
you have successfully bought 20 tickets
you have successfully bought 15 tickets
you have successfully bought 20 tickets
you have successfully bought 15 tickets
you have successfully bought 20 tickets
you have successfully bought 15 tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets
sorry,no enough tickets

In addition to using lock locked variable, you can also use try_lock locked variable, you can also use Mutex.synchronize synchronize access to a particular variable.

Regulatory data transfer of the Queue class implements Thread Synchronization

Queue class that represents a thread support queue, the queue can be synchronized to the end of the visit. Different threads can use a unified class, but do not worry about whether the data can be synchronized in this queue, in addition to limit the use of SizedQueue class queue length

SizedQueue class can be very convenient to help us develop threaded applications to synchronize, synchronization problems should be added to the long queue, you do not care about threads.

Classic producers and consumers:

#!/usr/bin/ruby

require "thread"
puts "SizedQuee Test"

queue = Queue.new

producer = Thread.new do
     10.times do |i|
          sleep rand(i) # 让线程睡眠一段时间
          queue << i
          puts "#{i} produced"
     end
end

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

consumer.join

Program output:

SizedQuee Test
0 produced
1 produced
consumed 0
2 produced
consumed 1
consumed 2
3 produced
consumed 34 produced

consumed 4
5 produced
consumed 5
6 produced
consumed 6
7 produced
consumed 7
8 produced
9 produced
consumed 8
consumed 9

Thread Variables

Thread can have its private variable, a thread private variable writing thread when the thread is created. It can be used within the scope of the thread, but the thread can not be shared externally.

But sometimes, the thread local variables do not need another thread or the main thread to access how to do? ruby allows them to create a thread is provided by the variable name, the thread is seen as similar style hash hash table. By [] = written by [] read data. We look at the following code:

#!/usr/bin/ruby

count = 0
arr = []

10.times do |i|
   arr[i] = Thread.new {
      sleep(rand(0)/10.0)
      Thread.current["mycount"] = count
      count += 1
   }
end

arr.each {|t| t.join; print t["mycount"], ", " }
puts "count = #{count}"

The above code is run output is:

8, 0, 3, 7, 2, 1, 6, 5, 4, 9, count = 10

The main thread waits for the child thread execution is completed, and then outputs each value. .


Thread priority

Thread's priority is the main factor affecting the thread scheduling. Other factors include the length of time to perform CPU-thread packet scheduling and so on.

You can use Thread.priority obtained a thread's priority and use Thread.priority = method to adjust the thread priority.

A thread's priority defaults to 0. Faster execution of higher priority.

A Thread can access all data within the scope of their own, but if there are other threads need to access data in a thread should be how to do it? Thread class provides thread data access each other, you can simply put a thread as a Hash table, can be used in any thread [] = Write data, use [] read data.

athr = Thread.new { Thread.current["name"] = "Thread A"; Thread.stop }
bthr = Thread.new { Thread.current["name"] = "Thread B"; Thread.stop }
cthr = Thread.new { Thread.current["name"] = "Thread C"; Thread.stop }
Thread.list.each {|x| puts "#{x.inspect}: #{x["name"]}" }

We can see, the thread as a Hash table, use [] and [] = method, we achieved data sharing between threads.


Thread mutex

Mutex (Mutal Exclusion = mutex) is a method for multi-threaded programming, a mechanism to prevent two threads simultaneously for the same public resources (such as global variables) read and write.

Examples of non-use Mutax

#!/usr/bin/ruby
require 'thread'

count1 = count2 = 0
difference = 0
counter = Thread.new do
   loop do
      count1 += 1
      count2 += 1
   end
end
spy = Thread.new do
   loop do
      difference += (count1 - count2).abs
   end
end
sleep 1
puts "count1 :  #{count1}"
puts "count2 :  #{count2}"
puts "difference : #{difference}"

Run the above example output is:

count1 :  9712487
count2 :  12501239
difference : 0

Example of Mutax

#!/usr/bin/ruby
require 'thread'
mutex = Mutex.new

count1 = count2 = 0
difference = 0
counter = Thread.new do
   loop do
      mutex.synchronize do
         count1 += 1
         count2 += 1
      end
    end
end
spy = Thread.new do
   loop do
       mutex.synchronize do
          difference += (count1 - count2).abs
       end
   end
end
sleep 1
mutex.lock
puts "count1 :  #{count1}"
puts "count2 :  #{count2}"
puts "difference : #{difference}"

Run the above example output is:

count1 :  1336406
count2 :  1336406
difference : 0

Deadlock

More than two operation units, both sides are waiting for the other to stop running, to get the system resources, but not a party early exit, this situation is called deadlock.

For example, a process p1 takes up display, while you must use the printer, and the printer is occupied by the process p2, p2 must also use the monitor, thus forming a deadlock.

When we use Mutex object needs attention thread deadlock.

Examples

#!/usr/bin/ruby
require 'thread'
mutex = Mutex.new

cv = ConditionVariable.new
a = Thread.new {
   mutex.synchronize {
      puts "A: I have critical section, but will wait for cv"
      cv.wait(mutex)
      puts "A: I have critical section again! I rule!"
   }
}

puts "(Later, back at the ranch...)"

b = Thread.new {
   mutex.synchronize {
      puts "B: Now I am critical, but am done with cv"
      cv.signal
      puts "B: I am still critical, finishing up"
   }
}
a.join
b.join

The above example output is:

A: I have critical section, but will wait for cv
(Later, back at the ranch...)
B: Now I am critical, but am done with cv
B: I am still critical, finishing up
A: I have critical section again! I rule!

Thread class method

Complete Thread (thread) class method as follows:

No. Method Description
1 Thread.abort_on_exception
If it is true, once a thread terminates due to an exception, the entire interpreter will be interrupted. The default value is false, that is, under normal circumstances, if a thread exception occurs and the exception is not Thread # join and other detected, the thread will be terminated without warning.
2 Thread.abort_on_exception =
If set totrue,once a thread terminates due to an exception, the entire interpreter will be interrupted. Returns new state
3 Thread.critical
Returns a Boolean value.
4 Thread.critical =
When the value is true, the thread will not be switched. If the current thread to hang (stop) or signal (signal) intervention, its value will be automatically changed to false.
5 Thread.current
Returns the current running thread (the current thread).
6 Thread.exit
It terminates the current thread. Returns the current thread. If the current thread is the only thread, using the exit (0) to terminate its operation.
7 Thread.fork {block}
Like with Thread.new generate threads.
8 Thread.kill (aThread)
Terminate the thread running.
9 Thread.list
Returns an array of live thread is running or suspended state.
10 Thread.main
Return to the main thread.
11 Thread.new ([arg] *) { | args | block}
Generate thread and begin execution. The number will be passed intact to the block. This can start a thread at the same time, the value will be passed to the local variables inherent in the thread.
12 Thread.pass
The right to run other threads. It does not change the state of the running threads, but will hand over control of other threads can run (Explicit thread scheduling).
13 Thread.start ([args] *) { | args | block}
Generate thread and begin execution. The number will be passed intact to the block. This can start a thread at the same time, the value will be passed to the local variables inherent in the thread.
14 Thread.stop
The current thread is suspended until the other threads run method again wake up the thread.

Thread instance method

The following example calls the thread instance method join:

#!/usr/bin/ruby

thr = Thread.new do   # 实例化
   puts "In second thread"
   raise "Raise exception"
end
thr.join   # 调用实例化方法 join

Here is a complete list of examples of the method:

No. Method Description
1 thr [name]
Remove the thread of the name corresponding to the inherent data. name can be a string or symbol. If the name does not correspond to the data, it returns nil.
2 thr [name] =
Set the thread name value in the corresponding characteristic data, name can be a string or symbol. If set to nil, removes the corresponding data in this thread.
3 thr.abort_on_exception
Returns a Boolean value.
4 thr.abort_on_exception =
If its value is true, then once a thread terminates due to an exception, the entire interpreter will be interrupted.
5 thr.alive?
If the thread is "live", it returns true.
6 thr.exit
Terminate the thread running. Returns self.
7 thr.join
Suspends the current thread until the self run until the thread terminates. If the self due to abnormal termination, the current thread will trigger the same exception.
8 thr.key?
If the name corresponding to the inherent data has been defined threads, then returns true
9 thr.kill
SimilarThread.exit.
10 thr.priority
Returns the thread's priority. The default priority is 0. The larger the value, the higher the priority.
11 thr.priority =
Setting the thread priority. You can also set it to negative.
12 thr.raise (anException)
Within this thread forcibly thrown.
13 thr.run
Restart Pending (stop) thread. The difference is that with the wakeup will conduct thread switching immediately. If using this method to process the dead will be raised ThreadError exception.
14 thr.safe_level
Returns self security level. Safe_level the current thread $ SAFE same.
15 thr.status
Using the string "run", "sleep" or "aborting" to indicate the status of the live thread if a thread is terminated normally, then it returns false. Ruoyin abnormal termination, then it returns nil.
16 thr.stop?
If the thread is terminated state (dead) or suspend (stop), the return true.
17 thr.value
Wait until the self thread terminates (equivalent to join), return the value of the block of the thread if the running threads occur during abnormal, the exception will be raised again.
18 thr.wakeup
The state is suspended (stop) of thread to the ready state (run), if the method is performed on the dead thread will raise ThreadError exception.