There are two ways to pass some data to a thread. You can either use the Thread constructor with the ParameterizedThreadStart delegate, or you can create a custom class and define the method of the thread as an instance method so that Y0′:l can initialize data of the instance before starting the thread. For passing data to a thread, any class or struct that holds the data is needed. Here, the struct Dat’a containing a string is defined, but you can pass any object you want:
If the par..ameterizedThreadStart delegate is used, the entry point of the thread must have a parameter of type object and a void return ype. The object can be cast to what it is, and here the message
is written to the console:
With the constructor of the Thread class, you can assign the new entry point ThreadMainWithParameters and invoke the Start () method passing the variable d:
Another way to pass data to the new thread is to define a class (see the class MyThread), where you define the fields that are needed as well as the main method of the thread as an instance method of the
This way, you can create an object of MyThread, and pass the object and the method ThreadMain () to the constructor of the Thread class. The thread can access the data.
The process of the application keeps running as long as at least one foreground thread is running. If more than one foreground thread is running and the Main () method ends, the process of the application
keeps active until all foreground threads finish their work. A thread you create with the Thread class, by default, is a foreground thread. Thread pool threads are
always background threads.
When you create a thread with the Thread class, you can define whether it should be a foreground or background thread by setting the property IsBackground. The Main () method sets the ISBatkground·
property of the thread tl to false (which is the default). After starting the new thread, the main thread just writes to the console an end message. The new thread writes a start and an end message, and in
between it sleeps for 3 seconds. The 3 seconds provide a good chance for the main thread to finish before the new thread completes its work.
When you start the application, you will still see the completion message written to the console, although the main thread completed its work earlier. The reason is that the new thread is a foreground thread as well.
M~in thread ending now…
If you change the IsBackground property to start the new thread to true, the result shown at the console is different. You can have the same result as shown here – the start message of the new thread is hown but never the end message. You might not see the start message either, if the thread was prematurely ended before it had a chance to kick off.
Marn thread ending now…
Background threads are very useful for background tasks. For example, when you close the Word application, it doesn’t make sense for the spell checker to keep its process running. The spell checker
thread can be killed when the application is closed. However, the thread organizing the Outlook message store should remain active until it is finished even if Outlook is closed.
Youhave learned that the operating system schedules threads. Youhave had a chance to influence the scheduling by assigning a priority to the thread. – Before changing the priority, you must understand the thread scheduler. The operating system schedules
threads based on a priority, and the thread with the highest priority is scheduled to run in the CPU. A thread stops running and gives up the CPU if it waits for a resource. There are several reasons why a
thread must wait; for example, in response to a sleep instruction, while waiting for disk I/O to complete, while waiting for a network packet to arrive, and so on. If the thread does not give up the CPU on its
own, it is preempted by the thread scheduler. If a thread does have a time quantum, it can use the CPU
continuously. If there are multiple threads running with the same priority waiting to get the CPU, the thread scheduler uses a round-robin scheduling principle to give the CPU to one thread after the other. If
a thread is preempted, it goes last to the queue. The time quantum and round-robin principles are used only if multiple threads are running at the same priority. The priority is dynamic. If a thread is CPU-intensive (requires the CPU continuously without waiting for resources), the priority is lowered to the level of the base priority that is defined with the thread. If a thread is waiting for a resource, the thread gets a priority boost and the priority is increased. Because of the boost, there is a good chance that the thread gets the CPU the next time that the wait ends. With the Thread class, you can influence the base priority of the thread by setting the Priority property. The Priori ty property requires a value that is defined by the ThreadPriori ty enumeration. The levels defined are Highest, AboveNormal, Normal, BelowNormal, and Lowest. Be careful when gii’illg a thread a higher priority, because this may decrease the chance for other threads to run. You call change the priority for a short time if neede
The thread is created by invoking the Start () method of a Thread object. However, after invoking the
Start () method, the new thread is still not in the Running state, but in the Unstarted state instead.
The thread changes to the Running state as soon as the operating system thread scheduler selects the
thread to run. You can read the current state of a thread by reading the property Thread. ThreadSta te.
With the Thread. S~eep () method, a thread goes into the wai tSleepJoin state and waits until it is
woken up again after the time span defined with the Sleep () method has elapsed.
To stop another thread, you can invoke the method Thread. Abort ( ) . When this method is called, an
exception of type ‘:’hreadAbortException is thrown in the thread that receives the abort. With a
handler to catch this exception, the thread can do some cleanup before it ends. The thread also has a
chance to continue running after receiving the ThreadAbortException as a result of invoking
Thread. ResetAbort ( ) . The state of the thread receiving the abort request changes from
Abo r t.Requ e s t ed to the Aborted state if the thread does not reset the abort.
If you need to wait for a thread to end, you can invoke the Thread. Join () method. Thread. Join ( )
blocks the current thread and sets it to the wai tSleepJoin state until the thread that is joined is
.NET 1.0 also supported ‘:’hread. Suspend () and Thread. Resume () methods to pause and continue a thread, respectively-However, you don’t know what the thread is doing when it gets the Suspend
request, and the thread might be in a synchronized section holding locks. This can easily result in deadlocks. That’s why these rr.ethods are now obsolete. Instead, you can signal a thread, using synchronization objects, so it can suspend itself. This way, the thread knows best when to go into a waiting state.