Ruby thread (1)

Source: Internet
Author: User

This chapter includes:

· Creating and Manipulating Threads

· Synchronizing Threads

· Summary

He draweth out the thread of his verbosity finer than the staple of his argument.

William Shakespeare, Love's Labours Lost, act 5, scene 1

Threads are sometimes called lightweight processes.
They are nothing more than a way to achieve concurrency without all
Overhead of switching tasks at the operating system level. (Of course,
The computing community isn' t in perfect agreement about the definition
Of threads; but we won't go into that .)

Ruby threads are user-level threads and depend on the operating system. They work on DOS and Unix. They will complete certain tasks, but they will also change with the operating system.

For example, threads are useful when separate code segments are separated. A thread is useful when an application spends too much time waiting for an event. Generally, when one thread is waiting, another thread may perform more useful processing.

In other words, using threads has potential advantages. The opposite of speed reduction is the benefit. Similarly, threads are not helpful when resources are continuously accessed. Finally, when synchronizing access to global resources is more important than other resources, use the thread.

For these and other reasons, some authors claim that thread-based programs can be avoided. The real synchronization code may be complex, prone to errors, and difficult to debug. But we will keep it for you to use these technologies at the right time.

The difficulties
Associated with unsynchronized threads are well-known. Global data can
Be upted by threads attempting simultaneous access to those data.
Race conditions can occur wherein one thread makes some assumption
About what another has done already; these commonly result in
"Non-deterministic" code that might run differently with each
Execution. Finally, there is the danger of deadlock, wherein no thread
Can continue because it is waiting for a resource held by some other
Thread that is also blocked. Code written to avoid these problems is
Referred to as thread-safe code.

Not
All of Ruby is thread-safe, but synchronization methods are available
That will enable you to control access to variables and resources,
Protect critical sections of code, and avoid deadlock. We will deal
With these techniques in this chapter and give code fragments
Using strate them.


 1. create and manage threads

Most basic operations of a thread include creating a thread, passing information in and out, stopping a thread, and so on. We can also get a thread list, check the thread status, and check other information. Here we will show you the basic operations.

1, Create thread

It is easy to create threads. We call the new method and append a block that will be used as the thread body.

Thread = Thread. new do

# Statements comprising

# The thread...

End

Obviously, the returned value is a Tread-type object, which is used by the main thread to control the thread it creates.
What if we want to pass parameters to the thread? We can do this by passing parameters to Thread. new, which passes them to the block.
A = 4
B = 5
C = 6
Thread2 = Thread. new (a, B, c) do | a, x, y |
# Manipulate a, x, and y as needed.
End
# Note that if a is changed in the new thread, it will
# Change suddenly and without warning in the main
# Thread.

It is similar to any other block parameter. Any one that matches the current variable will be effectively passed to the same variable. Variable a in the previous section is a dangerous variable in this case, as pointed out by annotations.

Threads can also access variables within the scope they are created. Obviously, it is not synchronous, which may be a problem. The main thread and one or more other threads may modify this variable independently of each other, and the result may be unpredictable.

X = 1
Y = 2
Thread3 = Thread. new do
# This thread can manipulate x and y from the outer scope,
# But this is not always safe.
Sleep (rand (0) # Sleep a random fraction of a second.
X = 3
End

Sleep (rand (0 ))
Puts x
# Running this code repeatedly, x may be 1 or 3 when it

# Is printed here!

The fork method is the alias of new, which is called by the same name in the famous Unix system.

2, Accessing Thread-local Variables

We know that it is dangerous for a thread to use variables out of its scope; we also know that the thread has its own local data. But how can a thread make its own data public?

There is a special mechanism for this purpose. If a thread object is treated as a hash table, the local data of the thread can be accessed from anywhere in the scope of the thread object. We are not saying that the real local data can be accessed in this way, but only that we have access to named data on a per-thread basis.

Another method is key ?, It tells us whether a given name is used in this thread.

In a thread, We must reference data in a way similar to a hash table. Using Threa. current will make it easier to do something.

Thread = Thread. new do
T = Thread. current
T [: var1] = "This is a string"
T [: var2] = 365
End
# Access the thread-local data from outside...
X = thread [: var1] # "This is a string"
Y = thread [: var2] #365.
Has_var2 = thread. key? ("Var2") # true
Has_var3 = thread. key? ("Var3") # false
Note that the data can be accessed from other threads, even after the threads that own them have died (as in this example ).
In addition to symbols (as you just saw), we can also use strings to identify local variables of the thread.
Thread = Thread. new do
T = Thread. current
T ["var3"] = 25
T [: var4] = "foobar"
End
A = thread [: var3] = 25
B = thread ["var4"] = "foobar"

Do not confuse these special names with real local variables.
Thread = Thread. new do
T = Thread. current
T ["var3"] = 25
T [: var4] = "foobar"
Var3 = 99 # True local variables (not
Var4 = "zorch" # accessible from outside)
End

A = thread [: var3] #25
B = thread ["var4"] # "foobar"

Finally, note that an object reference to a real local variable can be abbreviated as a stenographer in the thread. This is true, as long as you are careful to protect the reference of an object with the same name rather than creating a new one.

Thread = Thread. new do

T = Thread. current

X = "nXxeQPdMdxiBAxh"

T [: my_message] = x

X. reverse!

X. delete! "X"

X. gsub! (/[A-Z]/, "")

# On the other hand, assignment wocould create a new

# Object and make this shorthand useless...

End

A = thread [: my_message] # "hidden"

Similarly, this abbreviation obviously does not work. When you process a value such as Fixnums, it is stored as a direct value rather than an object reference.

 

 

3, Querying and Changing Thread Status

The Thread class has several Class methods that serve various purposes. The List method returns the List of all active threads. The main method returns the reference of the main thread that can generate other threads. The current method allows the thread to identify itself.

T1 = Thread. new {sleep 100}

T2 = Thread. new do

If Thread. current = Thread. main

Puts "This is the main thread." # Does NOT print

End

1. upto (1000)

Sleep 0.1

End

End

Count = Thread. list. size #3

If Thread. list. include? (Thread. main)

Puts "Main thread is alive." # Always prints!

End

If Thread. current = Thread. main

Puts "I'm the main thread." # Prints here...

End

The exit, pass, start, stop, and kill methods are used to control the running of threads (usually from internal or external ).

# In the main thread...

Thread. kill (t1) # Kill this thread now

Thread. pass (t2) # Pass execution to t2 now

T3 = Thread. new do

Sleep 20

Thread. exit # Exit the thread

Puts "Can't happen! "# Never reached

End

Thread. kill (t2) # Now kill t2

# Now exit the main thread (killing any others)

Thread. exit

Note that there is no instance method to stop, so a thread can stop itself but cannot stop other threads.

There are also various methods used to check the thread status. Instance method alive? Will it say whether the thread is still alive (not exist), stop? Indicates whether the thread is stopped.

Count = 0

T1 = Thread. new {loop {count + = 1 }}

T2 = Thread. new {Thread. stop}

Sleep 1

Flags = [t1.alive ?, # True

T1.stop ?, # False

T2.alive ?, # True

T2.stop?] # True

The status of the thread can be seen using the status method. If the thread is currently running, the returned value is "run"; if it is stopped, sleep, or waiting on I/O, it is "sleep "; if it is aborted by an exception, it is nil.

T1 = Thread. new {loop {}}

T2 = Thread. new {sleep 5}

T3 = Thread. new {Thread. stop}

T4 = Thread. new {Thread. exit}

T5 = Thread. new {raise "exception "}

S1 = t1.status # "run"

S2 = t2.status # "sleep"

S3 = t3.status # "sleep"

S4 = t4.status # false

S5 = t5.status # nil

Global Problem $ SAFE can be set in different threads. In this case, it is not a real global variable at all; but we should not complain, because it allows us to run threads with different security levels. The Saft_level method tells us the level of the running thread.

T1 = Thread. new {$ SAFE = 1; sleep 5}

T2 = Thread. new {$ SAFE = 3; sleep 5}

Sleep 1

Lev0 = Thread. main. safe_level #0

Lev1 = t1.safe _ level #1

Lev2 = t2.safe _ level #3

The thread priority may be checked and changed using the priority accessor.

T1 = Thread. new {loop {sleep 1 }}

T2 = Thread. new {loop {sleep 1 }}

T2.priority = 3 # Set t2 at priority 3

P1 = t1.priority #0

P2 = t2.priority #3

High-priority threads will be scheduled more.

When the thread wants to give control to the scheduler, it can use a special method to pass. The thread only gives its time slice; it does not really stop or sleep.

T1 = Thread. new do

Puts "alpha"

Thread. pass

Puts "beta"

End

T2 = Thread. new do

Puts "gamma"

Puts "delta"

End

T1.join

T2.join

In this example, when Thread. pass is called, the output order is alpha gamma delta beta. Without it, the order we get is alpha beta gamma delta. Of course, this feature should not be used for synchronization, but only for saving time slice allocation.

A stopped thread can be awakened by running or wakeup:

T1 = Thread. new do

Thread. stop

Puts "There is an emerald here ."

End

T2 = Thread. new do

Thread. stop

Puts "You're at Y2 ."

End

Sleep 1

T1.wakeup

T2.run

They are slightly different. Wakeup calls to modify the state of the thread so that it becomes runable, but does not schedule it to run; in other words, run wakes up the thread and schedules it to run immediately.

In special cases, the result is that t1 is awakened before t2, but t2 is scheduled first, and the output is as follows:

You're at Y2.

There is an emerald here.

Of course, don't be too stupid to try to use this tiny difference to synchronize.

The raise instance method causes an exception in the thread specified as the receiver. (This call does not have to happen within the thread .)

Factorial1000 = Thread. new do

Begin

Prod = 1

1. upto (1000) {| n | prod * = n}

Puts "1000! = # {Prod }"

Rescue

# Do nothing...

End

End

 

 

Sleep 0.01 # Your mileage may vary.

If factorial1000.alive?

Factorial1000.raise ("Stop! ")

Puts "Calculation was interrupted! "

Else

Puts "Calculation was successful ."

End

The previously generated thread attempts to calculate the 1000 factorial. If it is not completed within 100 seconds, the main thread will kill it. Therefore, on a relatively slow machine, the information printed by this code snippet will be Calculation was interrupted !. Concerning the rescue clause in the thread, it is obvious that we can place any code we need, just like other clauses.

 

 

4, Achieving a Rendezvous (and Capturing a Return Value)

Sometimes, the main thread wants to wait for the completion of another thread. Instance method join will complete these steps.

 

 

T1 = Thread. new {do_something_long ()}

Do_something_brief ()

T1.join # Wait for t1

Note: If the main thread waits on another thread, join is required. Otherwise, the thread is killed when the main thread exits. For example, when there is no join at the end of the clip, it will never give us the final answer:

Meaning_of_life = Thread. new do

Puts "The answer is ..."

Sleep 10

Puts 42

End

 

 

Sleep 9
Meaning_of_life.join

Here is a useful small syntax. It calls join in addition to the main thread in each active thread. (For any thread, even the main thread, this has an error. It calls join on itself ).

Thread. list. each {| t. join if t! = Thread. main}

Of course, when neither of them is a thread, it is feasible for a thread to join on another thread. If the main thread and another thread try to join each other, the result is a deadlock. The interpreter will detect this situation and exit the program.

Thr = Thread. new {sleep 1; Thread. main. join}

Thr. join # Deadlock results!

The thread has associated blocks and the blocks can return values. This means that the thread can return values. The value Method secretly performs the join operation and waits for the thread to complete. Then, it returns the value returned by the final computing expression in the thread.

Max = 10000

Thr = Thread. new do

Sum = 0

1. upto (max) {| I | sum + = I}

Sum

End

 

 

Guess = (max * (max + 1)/2

Print "Formula is"

If guess = thr. value

Puts "right ."

Else

Puts "right ."

End

 

5, Dealing with Exceptions

What happens if an exception occurs in the thread? It is disabled and its behavior is configurable.

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.