Each program that is 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 that runs multiple threads at the same time in a single program to accomplish different tasks, called multithreading.
In Ruby, we can create multiple threads through the thread class, and Ruby threads are lightweight and can be implemented in parallel code in an efficient way.
Creating a Ruby thread
To start a new thread, you only need to invoke Thread.new:
# thread #1 Code part
thread.new {
# thread #2 execute code
}
# thread #1 execute code
Instance
The following examples show 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 End-
def func2
j=0 while
j<=2
puts ' Func2 at: #{time.now} ' sleep
(1)
j=j+1
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 execution results are:
started at Wed could 08:21:54-0700 2014 func1 at:wed May 08:21:54-0700 2014 Func2 at:wed may
14 08:21:54- 0700 2014
FUNC2 at:wed May 08:21:55-0700 2014 func1 at:wed May 08:21:56-0700 2014 Func2 at:wed
08:21:56-0700 2014
func1 at:wed May 08:21:58-0700 2014 end at
Wed May 14 08:22:00-0700 2014
Thread life cycle
1. Threads can be created using thread.new, as well as using Thread.Start or thread.fork these three methods to create threads in the same syntax.
2, the thread is automatically executed when the thread is created without starting.
3. The thread class defines methods to manipulate threads. The thread executes the code block in the Thread.new.
4. The last statement in the thread code block is the value of the thread, which can be invoked by means of a thread, and if the thread completes, the thread value is returned, otherwise the value is not returned until the thread has finished executing.
5. The Thread.current method returns the object representing the current thread. The Thread.main method returns the main thread.
6, through the Thread.Join method to execute the thread, this method will suspend the main thread until the current thread execution completed.
Thread State
There are 5 states of threads:
Threads and exceptions
When a thread has an exception and is not captured by rescue, the thread is usually terminated without warning. However, if there are other threads waiting for the thread because of the thread#join relationship, the waiting thread will also throw the same exception.
Begin
T = thread.new
do thread.pass # main thread does wait for join
raise "Unhandled exception"
End
T.join
rescue
P $! # => "Unhandled exception"
end
Using the following 3 methods, you can have the interpreter break when a thread terminates because of an exception.
- Specifies the-d option when you start the script and runs when you debug the mode.
- Set the flag with Thread.abort_on_exception.
- Sets a flag for the specified thread using Thread#abort_on_exception.
When one of these 3 methods is used, the entire interpreter is interrupted.
t = thread.new {...}
T.abort_on_exception = True
Thread Synchronization Control
In Ruby, there are three ways to implement synchronization, respectively:
1. Implement thread synchronization through mutex classes
2. The queue class for monitoring data handover implements thread synchronization
3. Use conditionvariable to realize synchronous control
Thread synchronization through a mutex class
Thread synchronization control is implemented through the mutex class, and if you need a program variable at the same time for multiple line Chengzhong, you can lock the variable part with lock. The code is as follows:
#encoding: GBK
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
Thread.new do
10.times do |value|
Ticketnum=15
Buyticket (ticketnum) sleep
0.01
end
ticket2=thread.new
10. Times do |value|
Ticketnum=20
Buyticket (ticketnum) sleep 0.01 End sleep
1
ticket1.join
Ticket2.join
The output results are as follows:
Synchronize Thread your have successfully bought tickets you have successfully bought to
tickets you
have SU Ccessfully bought have successfully bought tickets you have successfully bought tickets
y OU have successfully bought tickets you have successfully bought tickets you have successfully bought
Kets have successfully bought tickets you have successfully bought a
tickets you
have successfully b Ought 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 locking a variable with lock, you can also use Try_lock to lock a variable, and you can use Mutex.synchronize to synchronize access to a variable.
the queue class that regulates data handover implements thread synchronization
The queue class is the one that represents a support thread and is able to synchronize access to the end of the queue. Different threads can use a unified pair of classes, but don't worry about whether the data in this queue can be synchronized, and use the Sizedqueue class to limit the length of the queue
The Sizedqueue class can be very handy to help us develop thread-synchronized applications, so you don't have to worry about thread synchronization as long as you join this queue.
The classic producer consumer problem:
#encoding: GBK
require "thread"
puts "Sizedquee Test"
queue = queue.new producer
= Thread.new
do 10.times do |i|
Sleep rand (i) # get the thread sleeping for a period of time
queue << i
puts "#{i} produced" End end
consumer = thread.new do< C12/>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 produced
consumed 4
5 produced
consumed 5
6 produced< C33/>consumed 6
7 produced
consumed 7
8 produced
9 produced
consumed 8
consumed 9
Using conditionvariable to implement synchronous control
Using conditonvariable for synchronous control, you can suspend threads until there is a resource available in some of the most lethal resource competition parts.
#encoding: GBK
require "thread"
puts "thread synchronize by conditionvariable"
mutex = mutex.new
Resource = conditionvariable.new
a = thread.new {
mutex.synchronize {
# This thread currently needs to resource this resource
Resource.wait (mutex)
puts "Get Resource"
}
}
B = thread.new {
mutex.synchronize {
# Thread B completes the use of the Resourece resource and releases resource
resource.signal
}
}
a.join
puts "complete"
A mutex is a declared resource and is then controlled by Conditionvariable to request and release the resource.
The b thread frees the resource resource.signal after some work has been done, so that a thread can obtain a mutex resource and execute it. Execution results:
Thread synchronize by Conditionvariable get
resource
complete
Thread class methods
The complete thread (thread) class method is as follows:
Thread Instantiation Method
The following instance invokes the thread instantiation method join:
#!/usr/bin/ruby
thr = thread.new do # instantiation
puts ' in second Thread '
raise ' raise exception '
end Thr.join # Invokes the instantiation method join
The following is a list of the full instantiation methods:
Thread Instantiation Method
The following instance invokes the thread instantiation method join:
#!/usr/bin/ruby
thr = thread.new do # instantiated
puts "in second Thread"
raise "
raise Exception" end< C16/>thr.join # Invokes the instantiation method join
The following is a list of the full instantiation methods: