Ruby multi-thread programming

Source: Internet
Author: User

Ruby multi-thread programming

A traditional program has a separate thread for execution. The statements or commands containing the program are executed sequentially until the program is terminated.

A multi-threaded program has multiple threads for execution. Each thread is executed in sequence, but the thread may be executed in parallel on a multi-core CPU machine. For example, in a single CPU machine, multiple threads are not executed in parallel, but are executed in parallel.

Ruby can use the Thread class to easily write multi-threaded programs. The Ruby thread is a lightweight and efficient method for implementing concurrency in code.
Create a Ruby thread:

To start a new Thread, associate a block by calling Thread. new. A new code block executed by the Thread will be created, and the original Thread will immediately return from Thread. new and continue to execute the next statement:

# Thread #1 is running hereThread.new { # Thread #2 runs this code}# Thread #1 runs this code

For example:

Here is an example of how we can use a multi-threaded Ruby program.

#!/usr/bin/rubydef func1  i=0  while i<=2   puts "func1 at: #{Time.now}"   sleep(2)   i=i+1  endenddef func2  j=0  while j<=2   puts "func2 at: #{Time.now}"   sleep(1)   j=j+1  endendputs "Started At #{Time.now}"t1=Thread.new{func1()}t2=Thread.new{func2()}t1.joint2.joinputs "End at #{Time.now}"

This produces the following results:

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

Thread lifecycle:

Create a new Thread using Thread. new. You can also use the synonyms Thread. Start and Thread. fork.

There is no need to start a thread. After it is created, it will automatically start running and CPU resources become available.

The Thread class defines some methods to query and process the threads at runtime. Run the code in a Thread block to call Thread. new, and then it stops running.

The value of the last expression in this block is the value of the Thread. You can call the method of the value of the Thread object. If the thread is completed, the value is the return value of the thread. Otherwise, the value method will block and will not return until the thread has completed.
Class Method Thread. current returns the Thread object of the current Thread. This allows the thread to manipulate itself. Class Method Thread. main the returned thread object represents the main Thread, and the initial thread Thread starts to execute the Ruby program.

Wait for a specific Thread to call the Thread. Join method of the Thread. The call thread is blocked until the specified thread is completed.
Thread and exception:

If an exception is thrown in the main thread, the Ruby interpreter prints a message and exits. In other threads other than the main thread, the thread stops running due to an unhandled exception.

If the thread t exits because of an unhandled exception and the other thread calls t. join or t. value, the exception occurs in the thread s proposed in t.

If Thread. abort_on_exception is false, the unhandled exception only kills the current Thread and all other tasks.

If you want to cause interpretation exit due to any unprocessed exceptions in any Thread, set the class method Thread. abort_on_exception to true.

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

Thread variable:

A thread can normally access any variable in the range when the thread is created. The local variable of a thread block is the local variable of the thread, rather than sharing.

The Thread class provides a special function that allows you to create and access local variables of a Thread by name. Just put the thread object. If it is a Hash, write the elements using [] = and read them back using [].

In this example, each thread records the current value of the counting variable and a threadlocal variable of the key mycount.

#!/usr/bin/rubycount = 0arr = []10.times do |i|  arr[i] = Thread.new {   sleep(rand(0)/10.0)   Thread.current["mycount"] = count   count += 1  }endarr.each {|t| t.join; print t["mycount"], ", " }puts "count = #{count}"

This will produce the following results:

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

The main thread waits for the sub-thread to complete, and then prints the value of each capture count.
Thread priority:

The first factor affecting thread scheduling is the thread priority: the thread with a low priority planned before the high priority. More specifically, a thread will only get the CPU time if there is no higher priority thread waiting for running.

You can set and query the priority = and priority of a Ruby thread object. The newly created thread starts to create it in a thread with the same priority. The priority of the main thread to be started is 0.

There is no way to set the thread priority before running. However, a thread can increase or lower its priority for the first operation.
Thread exclusion:

If two threads share access to the same data and at least one thread modifies the data, you must be very careful to ensure that no thread can see the data in an inconsistent state. This is called thread exclusion.

The Mutex class provides Mutex access to some shared resources and implements a simple signal lock. That is, only one thread can hold the lock at a given time. Other threads may choose to wait for the lock to become available, or you can simply choose to get an error immediately, indicating that the lock is unavailable.

By controlling all mutex that access Shared data, we ensure consistency and atomic operations. In our example, the first one does not require mutax, and the second one uses mutax:
Examples without Mutax:

#!/usr/bin/rubyrequire 'thread'count1 = count2 = 0difference = 0counter = Thread.new do  loop do   count1 += 1   count2 += 1  endendspy = Thread.new do  loop do   difference += (count1 - count2).abs  endendsleep 1puts "count1 : #{count1}"puts "count2 : #{count2}"puts "difference : #{difference}"

This produces the following results:

count1 : 1583766count2 : 1583766difference : 637992#!/usr/bin/rubyrequire 'thread'mutex = Mutex.newcount1 = count2 = 0difference = 0counter = Thread.new do  loop do   mutex.synchronize do     count1 += 1     count2 += 1   end  endendspy = Thread.new do  loop do    mutex.synchronize do     difference += (count1 - count2).abs    end  endendsleep 1mutex.lockputs "count1 : #{count1}"puts "count2 : #{count2}"puts "difference : #{difference}"

This produces the following results:

count1 : 696591count2 : 696591difference : 0

Handle deadlocks:

When we start to use the thread exclusion of mutex objects, we must be careful to avoid deadlocks. When a deadlock occurs, all threads are waiting to obtain the resources held by another thread. Because all threads are blocked, they cannot release the lock they hold. Because they can not release the locks, other threads cannot obtain these locks.

A condition variable is only a signal associated with resources and used within the protection range of a specific mutex lock. When a resource is required to be unavailable, wait for a condition variable. This action releases the corresponding mutex lock. When some other threads send signals to the resource is available, the original thread will wait and restore the lock critical zone at the same time.
Example:

#!/usr/bin/rubyrequire 'thread'mutex = Mutex.newcv = ConditionVariable.newa = 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.joinb.join

This produces the following results:

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

Thread status:

Five possible return values correspond to five possible states shown in the following table. The thread status returned by this status method.


Thread class method:

The Thread class provides the following methods, which apply to all threads of the program. These methods are called using the name of the Thread class, as shown below:

Thread.abort_on_exception = true

Here is a complete list of all class methods:

Thread instance method:

These methods are applicable to an instance of a thread. These methods will be called. An instance using a thread is as follows:

#!/usr/bin/rubythr = Thread.new do  # Calling a class method new  puts "In second thread"  raise "Raise exception"endthr.join  # Calling an instance method join

Here is a complete list of all instance methods:

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.