This article mainly introduces the initial introduction of Ruby multithreaded programming, thread is the focus of Ruby programming learning and difficult, the need for friends can refer to the
A traditional program has a separate thread that executes the statement or instruction sequence that contains the program until the program terminates.
A multithreaded program has multiple threads executing. Each thread is executed sequentially, but the multiple-core CPU machine thread may execute in parallel. For example, in the case of a single CPU machine, multiple threads are not actually executing in parallel, but rather simulating the execution of threads that intersect in parallel.
Ruby can easily write multithreaded programs using the Thread class. Ruby threads are a lightweight and efficient implementation of parallelism in your code.
To create a ruby thread:
To start a new thread, associate a block by calling Thread.new. A new thread execution code block will be created, and the original thread will immediately return from thread.new and continue execution of the next statement:
# Thread #1 is running here
Thread.new{
# Thread #2 runs this code
}
# Thread #1 runs this code
For example:
Here is an example of how we can take advantage of multithreaded ruby programs.
#!/usr/bin/ruby
deffunc1
i=0
whilei<=2
puts"func1 at: #{Time.now}"
sleep(2)
i=i+1
end
end
deffunc2
j=0
whilej<=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}"
This will produce the following results:
Started At Wed May1408:21:54-07002008
func1 at: Wed May1408:21:54-07002008
func2 at: Wed May1408:21:54-07002008
func2 at: Wed May1408:21:55-07002008
func1 at: Wed May1408:21:56-07002008
func2 at: Wed May1408:21:56-07002008
func1 at: Wed May1408:21:58-07002008
End at Wed May1408:22:00-07002008
Life cycle of Threads:
Create a new thread with the thread.new. Synonyms can also be used with Thread.Start and thread.fork.
It is not necessary to start a thread when it is created, it will automatically start running when CPU resources become available.
The thread class defines methods to query and process threads at run time. Run the code in a thread block to call Thread.new, and then it stops running.
The value of the last expression in the block is the value of the thread, which can be invoked by calling the method of the thread object value. If the thread runs complete, the value is the return value of the thread. Otherwise, the value method blocks and does not return until the thread has completed.
The class method thread.current returns a Thread object that represents the current thread. This allows the thread to manipulate itself. The class method Thread.main returns the thread object to represent the main thread, thread.this the initial thread starts executing the Ruby program.
You can wait for a particular thread to complete by calling the thread's Thread.Join method. The calling thread will be blocked until the given thread completes.
Threads and Exceptions:
If an exception is thrown in the main thread and there is no place to handle it, the Ruby interpreter prints a message and exits. In other threads other than the main thread, unhandled exceptions cause the thread to stop running.
If the thread t exits because of an unhandled exception and another thread calls T.join or T.value, then the exception that occurred in T is the thread s.
If Thread.abort_on_exception is false, by default, an unhandled exception kills only the current thread and all the rest continues to run.
The Set class method Thread.abort_on_exception is True if you want any unhandled exception in any thread to cause an explanation to exit.
t =Thread.new{ ... }
t.abort_on_exception =true
Thread variables:
A thread can normally be accessed when a thread of any variable within the scope is created. A local variable of a thread block is part of the thread, not a share.
The thread class provides a special feature that allows you to create and access thread-local variables by name. Simply put the thread object, if it is a hash, write the element using [] = and read them back with the use [].
In this example, each thread records the current value of the count variable with a threadlocal variable mycount the key.
#!/usr/bin/ruby
count =0
arr = []
10.timesdo|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}"
This will produce the following results:
|
8, 0, 3, 7, 2, 1, 6, 5, 4, 9, Count = 10 |
The main thread waits for the child thread to complete, and then prints out the value of each captured count.
Thread Priority:
The first factor that affects thread scheduling is the priority of a thread: a low-priority thread that was planned before a high-priority thread. Rather, a thread will only get CPU time if no higher priority thread is waiting to run.
You can set and query the priority = and priority of a Ruby thread object. The newly created thread starts to create it at the same priority thread. Start primary thread priority is 0.
There is no way to set the thread priority before it starts running. However, a thread can raise or lower its own priority for the first operation.
Thread repulsion:
If two threads share access to the same data, and at least one thread modifies the data, you must be particularly careful to ensure that no thread can see the data in an inconsistent state. This is called thread exclusion.
Mutex classes are mutually exclusive access to some shared resources and implement a simple signal lock. That is, only one thread can hold a lock at a given time. Other threads may choose to have a queued lock become available, or you can simply choose to get an error immediately, indicating that the lock is not available.
By controlling all the mutexes that access the shared data, we ensure consistency and atomic operations. Our trial example, the first one without Mutax, the second one uses mutax:
No mutax examples are required:
#!/usr/bin/ruby
require'thread'
count1 = count2 =0
difference =0
counter =Thread.newdo
loopdo
count1 +=1
count2 +=1
end
end
spy =Thread.newdo
loopdo
difference += (count1 - count2).abs
end
end
sleep1
puts"count1 : #{count1}"
puts"count2 : #{count2}"
puts"difference : #{difference}"
This will produce the following results:
count1 :1583766
count2 :1583766
difference :637992
#!/usr/bin/ruby
require'thread'
mutex = Mutex.new
count1 = count2 =0
difference =0
counter =Thread.newdo
loopdo
mutex.synchronizedo
count1 +=1
count2 +=1
end
end
end
spy =Thread.newdo
loopdo
mutex.synchronizedo
difference += (count1 - count2).abs
end
end
end
sleep1
mutex.lock
puts"count1 : #{count1}"
puts"count2 : #{count2}"
puts"difference : #{difference}"
This will produce the following results:
count1 :696591
count2 :696591
difference :0
Handling Deadlocks:
When we start using the thread exclusion of mutexes, we have to be careful to avoid deadlocks. When a deadlock occurs, all threads are waiting to acquire resources held by another thread. Because all threads are blocked, they cannot release the locks they hold. Because they can not release the lock, other threads cannot obtain these locks.
A condition variable is simply a signal that is associated with a resource and is used within the protection of a particular mutex. When a resource is not available, wait for a condition variable. This action frees up the corresponding mutex lock. When some other thread sends a signal to the resource that is available, the original thread waits and restores the critical section on the lock at the same time.
Example:
#!/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
This will produce the following results:
A:Ihave critical section, but will waitforcv
(Later, back at the ranch...)
B: NowIam critical, but am done with cv
B:Iam still critical, finishing up
A:Ihave critical section again!Irule!
Thread State:
There are five possible return values that correspond to the 5 possible states shown in the following table. The thread state returned by the State method.
Methods of the Thread class:
The thread class provides the following methods, which apply to all threads of the program. These methods are invoked using the name of the thread class, as follows:
Thread.abort_on_exception =true
Here is a complete list of all class methods:
Thread instance method:
These methods apply to one instance of a thread. These methods will be invoked, using an instance of one thread as follows:
#!/usr/bin/ruby
thr =Thread.newdo # Calling a class method new
puts"In second thread"
raise"Raise exception"
end
thr.join # Calling an instance method join
Here is a complete list of all instance methods: