Preliminary introduction to multithreading in Ruby programming and multithreading in ruby Programming
Every program running on the system is a process. Each process contains one or more threads.
A thread is a single sequential control process in a program. It runs multiple threads in a single program to complete different tasks at the same time. It is called multithreading.
In Ruby, we can use the Thread class to create multithreading. The Ruby Thread is lightweight and can implement parallel code in an efficient way.
Create a Ruby thread
To start a new Thread, you only need to call Thread. new:
# Thread #1 code Part Thread. new {# Thread #2 Execution Code} # Thread #1 Execution Code
Instance
The following example shows how to use multithreading in a Ruby program:
#!/usr/bin/ruby def func1 i=0 while i<=2 puts "func1 at: #{Time.now}" sleep(2) i=i+1 endend def func2 j=0 while j<=2 puts "func2 at: #{Time.now}" sleep(1) j=j+1 endend puts "Started At #{Time.now}"t1=Thread.new{func1()}t2=Thread.new{func2()}t1.joint2.joinputs "End at #{Time.now}"
The code execution result is:
Started At Wed May 14 08:21:54 -0700 2014func1 at: Wed May 14 08:21:54 -0700 2014func2 at: Wed May 14 08:21:54 -0700 2014func2 at: Wed May 14 08:21:55 -0700 2014func1 at: Wed May 14 08:21:56 -0700 2014func2 at: Wed May 14 08:21:56 -0700 2014func1 at: Wed May 14 08:21:58 -0700 2014End at Wed May 14 08:22:00 -0700 2014
Thread Lifecycle
1. You can use Thread. new to create a Thread. You can also use Thread. start or Thread. fork in the same syntax to create a Thread.
2. After a thread is created, it does not need to be started. The thread will be automatically executed.
3. The Thread class defines some methods to manipulate the Thread. The Thread executes the code block in Thread. new.
4. The last statement in the thread code block is the thread value, which can be called through the thread method. If the thread execution is complete, the thread value is returned. Otherwise, the return value is not returned until the thread execution is complete.
5. The Thread. current Method returns the object of the current Thread. The Thread. main method returns the main Thread.
6. Use the Thread. Join method to execute a Thread. This method suspends the main Thread until the current Thread is executed completely.
Thread status
The thread has five states:
Thread and exception
When a thread encounters an exception and is not captured by the rescue, the thread is usually terminated without warning. However, if other threads keep waiting for this Thread because of the Thread # join relationship, the waiting Thread will also be thrown with the same exception.
Begin t = Thread. new do Thread. pass # The main Thread is indeed waiting for join raise "unhandled exception" end t. joinrescue p $! # => "Unhandled exception" end
The following three methods can be used to interrupt the interpreter when a thread ends due to an exception.
- Specify the-d option when starting the script and run it in the debug mode.
- Use Thread. abort_on_exception to set the flag.
- Use Thread # abort_on_exception to set a flag for the specified Thread.
When one of the above three methods is used, the entire interpreter will be interrupted.
t = Thread.new { ... }t.abort_on_exception = true
Thread Synchronization Control
In Ruby, three synchronization methods are provided:
1. Implement Thread Synchronization Through the Mutex class
2. Implement thread synchronization for the Queue class that supervises Data Transfer
3. Use ConditionVariable for synchronization control
Implement Thread Synchronization Through the Mutex class
Use the Mutex class to implement thread synchronization control. If you need a program variable at the same time in multiple thread clocks, you can use lock to lock this variable. The Code is as follows:
#encoding:gbkrequire "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.unlockend ticket1=Thread.new 10 do 10.times do |value| ticketNum=15 buyTicket(ticketNum) sleep 0.01 endend ticket2=Thread.new 10 do 10.times do |value| ticketNum=20 buyTicket(ticketNum) sleep 0.01 endend sleep 1ticket1.jointicket2.join
The output result is as follows:
Synchronize Threadyou have successfully bought 15 ticketsyou have successfully bought 20 ticketsyou have successfully bought 15 ticketsyou have successfully bought 20 ticketsyou have successfully bought 15 ticketsyou have successfully bought 20 ticketsyou have successfully bought 15 ticketsyou have successfully bought 20 ticketsyou have successfully bought 15 ticketsyou have successfully bought 20 ticketsyou have successfully bought 15 ticketssorry,no enough ticketssorry,no enough ticketssorry,no enough ticketssorry,no enough ticketssorry,no enough ticketssorry,no enough ticketssorry,no enough ticketssorry,no enough ticketssorry,no enough tickets
In addition to lock variables, you can also use try_lock to lock variables. You can also use Mutex. synchronize to synchronize access to a variable.
Implement thread synchronization for the Queue class that supervises Data Transfer
The Queue class is a Queue that supports threads and can access the end of the Queue synchronously. Different threads can use a uniform pair of classes, but do not worry about whether the data in this queue can be synchronized. In addition, the SizedQueue class can limit the length of the queue.
The SizedQueue class can easily help us develop applications for thread synchronization. It should be that as long as we are added to this queue, we don't have to worry about thread synchronization.
Typical producer and consumer problems:
# Encoding: gbkrequire "thread" puts "SizedQuee Test" queue = Queue. new producer = Thread. new do 10. times do | I | sleep rand (I) # Let the Thread sleep for a period of time queue <I puts "# {I} produced" endend consumer = Thread. new do 10. times do | I | value = queue. pop sleep rand (I/2) puts "consumed # {value}" endend consumer. join program output: SizedQuee Test0 produced1 producedconsumed 02 producedconsumed 1 consumed 23 producedconsumed 34 produced consumed 45 producedconsumed 56 producedconsumed 67 producedconsumed 78 produced9 producedconsumed 8 consumed
Use ConditionVariable for synchronization control
Using ConditonVariable for synchronization control, the thread can be suspended in some fatal resource competition until there are available resources.
# Encoding: gbkrequire "thread" puts "thread synchronize by ConditionVariable" mutex = Mutex. newresource = ConditionVariable. new a = Thread. new {mutex. synchronize {# This thread currently needs resource. wait (mutex) puts "get resource"} B = Thread. new {mutex. synchronize {# thread B used the resourece resource and released the resource. signal}. joinputs "complete"
Mutex is a declared resource, and then uses ConditionVariable to control the application and release of this resource.
After thread B completes some work, it releases resource. signal, so that thread a can obtain a mutex resource and execute it. Execution result:
thread synchronize by ConditionVariableget resourcecomplete
Thread method
The complete Thread class method is as follows:
Thread instantiation Method
The following example calls the thread instantiation method join:
#! /Usr/bin/ruby thr = Thread. new do # instantiate puts "In second thread" raise "Raise exception" endthr. join # Call the instantiation method join
The following is a list of complete instantiation methods:
Thread instantiation Method
The following example calls the thread instantiation method join:
#! /Usr/bin/ruby thr = Thread. new do # instantiate puts "In second thread" raise "Raise exception" endthr. join # Call the instantiation method join
The following is a list of complete instantiation methods: