Updated at: February 23, 2017
Let’s start with a basic simple.
#sample1
cnt1=cnt2=0
diff=0
counter=Thread.new do
loop do
cnt1+=1
cnt2+=1
end
end
spy=Thread.new do
loop do
diff+=(cnt1-cnt2).abs
end
end
sleep 1
counter.exit
spy.exit
puts "count1: #{cnt1}"
puts "count2: #{cnt2}"
puts "diff: #{diff}"
I create two threads counter and spy here. First thread keep adding 1 for two variables and second one record the diffrence between cnt1 and cnt2.
Idealy
the result of sample1:
count1: 18514976
count2: 18514976
diff: 0
oops…, if you run this code on a single core machine, maybe get what you want to see here.The gap between two varialbes’increment is so tiny that thread2 can’t capture it.So let’s enlarge the gap by using a counter array.
#sample2
cnt=[]
diff=0
1000.times do
cnt<<0
end
counter=Thread.new do
loop do
cnt.map!{|c| c+1}
end
end
spy=Thread.new do
loop do
diff+=(cnt.first-cnt.last).abs
end
end
sleep 1
counter.exit
spy.exit
puts "count1: #{cnt.first}"
puts "count2: #{cnt.last}"
puts "diff: #{diff}"
No big change here. Just for thread1, we need to add 1 to 1000 instead of 2 variables in each loop this time.
count1: 8318
count2: 8317
diff: 5753627
This time thread2 capture the inconsistence.
How to permit data inconsistence while using multi-thread?
basic idea is that thread lock the resource when access it, so other resoure can’t access the same resource until the previous thread release lock. We can use Mutex to do this.
cnt=[]
diff=0
mutex=Mutex.new
1000.times do
cnt<<0
end
counter=Thread.new do
loop do
mutex.synchronize do
cnt.map!{|c| c+1}
end
end
end
spy=Thread.new do
loop do
mutex.synchronize do
diff+=(cnt.first-cnt.last).abs
end
end
end
sleep 1
mutex.lock
puts "count1: #{cnt.first}"
puts "count2: #{cnt.last}"
puts "diff: #{diff}"
The block between mutex.synchronize do and end called access shared resource. When thread1 is writing cnt[], thread2 can’t read it at sametime since it’s locked.
count1: 15411
count2: 15411
diff: 0
how to check each thread’s acual cpu usage on a multi-core machine?
Please assign a large number to sleep to let the process run longer.And utlize linux built-in ps.
> ps -ef|grep ruby|grep -v 'grep'
ghluo 11656 8350 99 03:44 pts/18 00:00:41 ruby multi_thread.rb
> ps -p 11656 -L -o pid,tid,psr,pcpu
PID TID PSR %CPU
11656 11656 2 0.0
11656 11657 1 0.0
11656 11658 0 98.8
11656 11659 3 4.9
# psr is assigned cpu id
# single thread ruby program will have two threads(one is the main process, another one should be ruby interpreter i think),similarly double thread program should have 4 threads(main+interpreter+2).