Thread Safety of Ruby Multi-threaded shared objects

Source: Internet
Author: User
Tags mutex

When you are sharing objects in multi-threaded processing, multiple threads can modify the same object at the same time, possibly in an inconsistent state, and be aware of it when used.

Example:

Test.rb

x = 010.times.map do |i|  Thread.new do    puts "before (#{i}): #{x}"    x + = 1    puts "after (#{i}): #{x}"  Endend.each (&:join) p UTS "\ntotal: #{x}"
Execute Ruby TEST.RB

Output:

Before (1): 0after (1): 1before (0): 1after (0): 2before (2): 2after (2): 3before (4): 3after (4): 4before (6): 4before (5 ): 3before (9): 3before (8): 3before (7): 3after (7): 6before (3): 3after (3): 7after (9): 5after (8): 8after (6): 9after (5): 10total:10

You may have noticed that in the fourth cycle, I = 3, the output:

Before (3): 3 #x等于3
After (3): 7 #x等于7

A mutex is a class that implements a simple signal lock for mutual access of some shared resources. In other words, only one thread can hold a lock at a given time. Other threads may choose to wait for the lock line to become available, or may simply choose an error that indicates that a lock cannot be used immediately.
By sharing the data under a mutually exclusive control of all accesses, we can ensure consistency and atomic manipulation, placing the code in the Synchorize method of the mutex object.

Modify the contents of the Test.rb file as follows:

x = 0mutex = Mutex.new10.times.map do |i|    Thread.new do mutex.synchronize do puts "before (#{i}): #{x}" x + = 1 puts "After (#{i}): #{x}" End Endend.each (&:join) puts "\ntotal: #{x}"

Execute Ruby TEST.RB

Output:

Before (0): 0after (0): 1before (9): 1after (9): 2before (2): 2after (2): 3before (3): 3after (3): 4before (4): 4after (4) : 5before (5): 5after (5): 6before (6): 6after (6): 7before (7): 7after (7): 8before (8): 8after (8): 9before (1): 9after (1): 10total:10
Here is an example of a counter:

The contents of the App.rb file are as follows:

Class Counter  attr_reader:total    def initialize    puts ' initialized ... '    @total = 0    @mutex = Mutex.new  End    def increment!    @mutex. Synchronize {@total + = 1}  endendclass application  def counter    @counter | | = Counter.new  End    def increment!    counter.increment!  End    def total    counter.total  Endendapp = Application.new10.times.map do |i|  Thread.new do    app.increment!  Endend.each (&:join) puts App.total
Performing Ruby app.rb Sometimes results in this:
Initialized...initialized...initialized...initialized...initialized...initialized...initialized...initialized ..... initialized ... 1
This result is wrong, counter uses a thread, but the final application is not, because we use | | =, it is not atomic. Application two instances see the @counter are nil, so all are instantiated counter, so the result is wrong.

The correct thing is to change the application to this:

Class Application  def initialize    @counter = counter.new  End    def counter    @counter  End    def increment!    counter.increment!  End    def total    counter.total  endend
This will instantiate the counter when the application is instantiated.

Executed again, the results are as follows:

Initialized ... 10

Handling Deadlocks:

When we start using mutex objects for thread repulsion, we must be careful to avoid deadlocks. A deadlock condition occurs when all threads are waiting to acquire resources held by another thread. Because all the threads are blocked, they cannot release the locks they hold. No other threads can acquire these locks because they cannot release the locks.
A condition variable is a simple related resource and a signal that is within the scope of protection for a particular mutex. When the resource you need is unavailable, you wait for a condition variable. This action frees the corresponding mutex. When other threads signal that the resource is available, the original thread waits, while resuming the lock on the critical section.

The Conditionvariable class implements the function of a state variable that supports thread synchronization. A Conditionvariable object is a product that materializes the waiting conditions of a thread.

Mutex = MUTEX.NEWCV = ConditionVariable.newThread.start {    mutex.synchronize {      ...      While (when conditions are not met)        cv.wait (m)      end      ...    }}
As shown above, if a thread has not satisfied the condition, call the wait method to suspend it and have the other thread execute
Thread.Start {    mutex.synchronize {      # does some action to satisfy the above conditions      cv.signal    }}

Then call the signal method to notify the waiting thread that the above conditions have been established. This is a more typical usage.

Reference: http://lucaguidi.com/2014/03/27/thread-safety-with-ruby.html


Thread Safety of Ruby Multi-threaded shared objects

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.