home PYTHONJAVA
 

Ruby multithreading

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 simultaneously in a single program to perform different tasks, called multithreading.

Ruby can create multithreading through the Thread class. Ruby threads are lightweight and can implement parallel code in an efficient way.


Create a Ruby thread

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

# Thread #1 Code Section Thread.new { # Thread #2 Execution Code } # Thread #1 Execution Code

Instance

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

Instance

#!/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 execution result is:

Started At Wed May 14 08:21:54< /span> -0700 /span>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, thread creation can use Thread.new, you can also use the same syntax to create threads using Thread.start or Thread.fork.

2. After the thread is created, there is no need to start, and the thread will execute automatically.

3, the Thread class defines methods to manipulate threads. The thread executes the code block in Thread.new.

4, the last statement in the thread code block is the value of the thread, which can be called by the thread method. If the thread finishes executing, the thread value is returned. Otherwise, the value is not returned until the thread finishes executing.

5, Thread.current method returns an object representing the current thread. The Thread.main method returns the main thread.

6. Execute the thread through the Thread.Join method. This method suspends the main thread until the current thread finishes executing.


Thread Status

Threads have 5 states:

Thread StatusReturn Value
Executablerun
SleepSleeping
Exitaborting
Normal terminationfalse
Abortednil

Threads and Exceptions

When an exception occurs on a thread and is not caught by the rescue, the thread is usually terminated without warning. However, if other threads are waiting for the thread because of the Thread#join relationship, the waiting thread will also be thrown the same exception.

begin t = Thread.new do Thread.pass # The main thread is indeed waiting for join raise "unhandled exception" end t.join rescue p $! # => "unhandled exception" end

The following three methods are used to allow the interpreter to break when a thread terminates due to an exception.

  • Specify the -d option when starting the script and run it with debug mode.
  • Set the flag with Thread.abort_on_exception.
  • Use Thread#abort_on_exception to set a flag for the specified thread.

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

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

Thread Synchronization Control

In Ruby, there are three ways to achieve synchronization, namely:

1. Thread synchronization via the Mutex class

2. Queue class for supervising data transfer to achieve thread synchronization

3. Synchronization Control with ConditionVariable

Thread synchronization through the Mutex class

Thread synchronization control through the Mutex class. If you need a program variable at the same time in multiple thread clocks, you can use this lock part to lock it. The code is as follows:

Instance

#!/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,n 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< /div>

The above code execution result is:

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,nolimited tickets
Sorry,nolimited tickets
Sorry,nolimited tickets
Sorry,nolimited tickets
Sorry,nolimited tickets
Sorry,nolimited tickets
Sorry,nolimited tickets
Sorry,nolimited tickets
Sorry,nowhere tickets

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

The Queue class that supervises data transfer implements thread synchronization

The Queue class is a queue that supports threads and can synchronize access to the end of the queue. Different threads can use a pair of classes, but don't 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 is very convenient for us to develop thread-synchronized applications. It should be added to this queue, so we don't care about thread synchronization.

Classic producer consumer issues:

Instance

#!/usr/bin/ruby require "thread" puts "SizedQuee Test" queue= Queue.new producer = Thread.new do 10.times do |i| sleep rand(i) # Let the thread sleep for a while 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
0produced
1produced
Consumed 0
2produced
Consumed 1
Consumed 2
3produced
Consumed 34produced

Consumed 4
5produced
Consumed 5
6produced
Consumed 6
7produced
Consumed 7
8produced
9produced
Consumed 8
Consumed 9

thread variable

A thread can have its own private variable, and the thread's private variable is written to the thread when the thread is created. Can be used within the scope of a thread, but cannot be shared outside the thread.

But sometimes, what if the thread's local variables need to be accessed by another thread or the main thread? Ruby provides a hash table that allows you to create thread variables by name, similar to threading as a hash. The data is read by []=write and by []. Let's take a look at the following code:

Instance

#!/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 runs and the output is:

8, 0, 3, 7,< /span> 2, < /span>1, 6 , 5 , 4, 9, count = 10

The main thread waits for the child thread to complete execution and then outputs each value separately. .


Thread priority

The priority of a thread is a major factor affecting the scheduling of threads. Other factors include the length of execution time occupied by the CPU, thread group scheduling, and so on.

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

The priority of the thread defaults to 0 . Higher priority execution is faster.

A Thread can access all the data in its scope, but what if you need to access data from other threads within a thread? The Thread class provides a way for thread data to access each other. You can simply use a thread as a hash table. You can use []= to write data in any thread and [] to 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"] }" }

As you can see, using threads as a Hash table, using the [] and []= methods, we implement data sharing between threads.


Thread mutual exclusion

Mutex (Mutal Exclusion = Mutex) is a mechanism used in multi-threaded programming to prevent two threads from reading and writing to the same common resource (such as global variables) at the same time.

Do not use an instance of Mutax

Instance

#!/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}"

The above example runs the output as:

count1 : 9712487
Count2 : 12501239
Difference : 0

Use an example of Mutax

Instance

#!/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}"

The above example runs the output as:

count1 : 1336406
Count2 : 1336406
Difference : 0

Deadlock

Two or more arithmetic units, both of which are waiting for the other party to stop running to obtain system resources, but when no one quits early, this situation is called deadlock.

For example, a process p1 occupies the display, and the printer must be used at the same time, and the printer is occupied by the process p2, and p2 must use the display, thus forming a deadlock.

When we are using Mutex objects, we need to pay attention to thread deadlocks.

Instance

#!/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< /div>

The output of the above example 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

The complete Thread class method is as follows:

serial numbermethod description
1Thread.abort_on_exception
If the value is true, the entire interpreter will be interrupted once a thread terminates due to an exception. . Its default value is false, that is, under normal circumstances, if a thread has an exception and the exception is not detected by Thread#join, etc., the thread will be terminated without warning.
2Thread.abort_on_exception=
If set to true, once a thread terminates due to an exception, the entire The interpreter will be interrupted. Return to new status
3Thread.critical
Returns a Boolean value.
4Thread.critical=
When the value is true, no thread switching will occur. If the current thread is stopped or signaled, its value will automatically change to false.
5Thread.current
Returns the currently running thread (current thread).
6Thread.exit
Terminates the current thread. Returns the current thread. If the current thread is the only one thread, it will use exit(0) to terminate its operation.
7Thread.fork { block }
Generate threads like Thread.new.
8Thread.kill( aThread )
Terminates thread execution.
9Thread.list
Returns an array of live threads in a running or suspended state.
10Thread.main
Return to the main thread.
11Thread.new( [ arg ]* ) {| args | block }
Generate the thread and start execution. The number is passed to the block as it is. This allows the value to be passed to the local variables inherent to the thread while the thread is starting.
12Thread.pass
Hands the run to other threads. It doesn't change the state of the running thread, it will control The right is handed over to other runnable threads (explicit thread scheduling).
13Thread.start( [ args ]* ) {| args | block }
Generate the thread and start execution. The number is passed to the block as it is. This allows the value to be passed to the local variables inherent to the thread while the thread is starting.
14Thread.stop
Suspends the current thread until another thread wakes up the thread again using the run method.

Thread instantiation method

The following example calls the thread instantiation method join:

Instance

#!/usr/bin/ruby thr = Thread.new do # Instantiation < /span> puts "In second thread" raise "Raise exception" end thr.join # Call the instantiation method join

The following is a complete list of instantiation methods:

< /tr>
serial numbermethod description
1thr[ name ]
Retrieve the intrinsic data corresponding to the name in the thread. Name can be a string or a symbol. Returns nil if there is no data corresponding to name.
2thr[ name ] =
Set the value of the intrinsic data corresponding to the name in the thread. The name can be a string or a symbol. If set to nil, the corresponding data in the thread will be deleted.
3thr.abort_on_exception
Returns a Boolean value.
4thr.abort_on_exception=
If its value is true, once a thread terminates due to an exception, the entire interpreter will be Interrupted.
5thr.alive?
If the thread is "live", it returns true.
6thr.exit
Terminates the thread from running. Return self.
7thr.join
Suspend the current thread until the self thread terminates. If self terminates due to an exception, it will be current The thread throws the same exception.
8thr.key?
If the thread-specific data corresponding to the name has been defined, it returns true
9thr.kill
is similar to Thread.exit .
10thr.priority
Returns the priority of the thread. The default value of priority is 0. The higher the value, the higher the priority. .
11thr.priority=
Set the priority of the thread. You can also set it to a negative number.
12thr.raise( anException )
Forcing an exception in this thread.
13thr.run
Restart the thread that was suspended. Unlike wakeup, it will immediately thread. Switch. If this method is used for a dead process, a ThreadError exception will be thrown.
14thr.safe_level
Returns the security level of self. The current thread's safe_level is the same as $SAFE.
15thr.status
Use the string "run", "sleep" or "aborting" to indicate the state of a live thread. If the thread terminates normally, it returns false. If it terminates due to an exception, it returns nil.
16thr.stop?
If the thread is in a dead state or is stopped, it returns true.
17thr.value
After the self thread terminates (equivalent to join), it returns the return value of the block of the thread. An exception occurs during the running of the thread, and the exception is raised again.
18thr.wakeup
Change the state of the thread that was suspended to the executable state (run), if it is dead When a thread executes this method, it will raise a ThreadError exception.





welookups is optimized for learning.© welookups. 2018 - 2019 All Right Reserved and you agree to have read and accepted our term and condition.