Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Microsoft C# Professional Projects - Premier Press.pdf
Скачиваний:
177
Добавлен:
24.05.2014
Размер:
14.65 Mб
Скачать

102

Part II

HANDLING DATA

 

 

 

FIGURE 6-2 Output of the previous code

When you call the methods of the Thread class, the state of the thread changes. For example, before you start a thread, the thread is not running. After you call the Start() method, the state of the thread changes to Running. This state changes further when you call the Suspend() or Abort() methods. In other words, whenever you perform an action on the thread, its state changes. The next section discusses the various states of a thread in detail.

Thread States

The change in the state of a thread results from the action performed on the thread. In other words, when you call a method of the Thread class, it changes the state of the thread. Figure 6-3 shows the effect of various methods of the Thread class on the states of a thread.

You have seen that you can suspend, sleep, or abort a running thread. However, if you do not want any other user to change the state of your thread, you can set the priority of your thread to Highest. The following section discusses thread priorities in detail.

Thread Priorities

The thread priorities define the sequence of executing various threads on a system. For example, if you have two threads running on a system, the thread with higher priority is executed first. C# allows you to set different priorities for different threads running simultaneously on your system.

THREADS

Chapter 6

103

 

 

 

FIGURE 6-3 Effect of methods on the states of a thread

The priority levels supported by C# are as follows:

Highest. A thread with the Highest priority is executed first. When the C# compiler finds the thread with the Highest priority, it stops executing all other threads until the thread with the Highest priority is executed.

AboveNormal. A thread with the AboveNormal priority is executed before any other threads except the thread with the Highest priority.

Normal. A thread with the Normal priority is third in the priority list. This thread is given a time slice according to the process of preemptive multitasking.

BelowNormal and Lowest. A thread with the BelowNormal or Lowest priority is executed only if the operating system does not encounter any other thread with a higher priority. You normally assign these priority levels to threads whose execution is not important to the system.

All of the priority levels mentioned here are a part of an enumeration object

known as ThreadPriorityEnumeration.

You can see that the priority levels can be set to define the sequence of execution of threads. However, the priority levels that you set are only applicable to the

104

Part II

HANDLING DATA

 

 

 

threads of a single process. For example, if you have a multithreaded application with five threads, the sequence in which these threads will be executed is affected by the priority levels. A thread with a higher priority does not affect the execution of threads of another application running on the system.

You can change the priority of a thread by specifying the value in the ThreadPriority property of the thread. To understand the syntax of the ThreadPriority property, look at the following example:

Thread Thread1 = new Thread(new ThreadStart(newClass.Method1));

Thread1.Priority = ThreadPriority.Highest;

The previous code sets the priority of Thread1 as Highest. This stops the execution of all the threads with a lower priority level until Thread1 is executed.

CAUTION

You should be very careful while setting priorities because specifying a priority level of Highest stops the execution of all the threads running on a system.

You have seen that by specifying the priority level of threads, you can set the sequence of executing multiple threads on your system. In addition to setting the priority levels, you need to synchronize multiple threads.This ensures smooth and bug-free execution of multiple threads simultaneously. The next section will help you understand the concept of synchronization so that the operating system does not encounter any problems while executing multithreaded applications.

Synchronization

As the name suggests, synchronization helps you to synchronize the use of variables and objects accessed by multiple threads running on your system. In simpler words, synchronization ensures that a variable can be accessed by only one thread at a time. Therefore, by preventing multiple threads from accessing a single variable, you can ensure bug-free execution of the threads on your system.

To understand the need for synchronization, consider a scenario in which two threads with the same priority, thread1 and thread2, are running simultaneously on a system. When the first thread is executed in its time slice, it may write some value to a public variable, variable1. However, in the next time slice, the other

THREADS

Chapter 6

 

105

 

 

 

 

 

thread might try to read or write a value to variable1. This situation can result in an error if the process of writing a value to variable1 is not completed in the first time slice. When another thread reads this variable, it may read the w rong value, resulting in an error. This situation can be avoided by synchronizing the use of variable1 by only one thread.

C# provides you with the lock keyword to synchronize the use of variables and objects. The lock statement takes the name of the object or variable to be locked as a parameter by the lock keyword. The name of the variable is enclosed in parentheses as shown in the following example:

lock (variable1)

{

------------

}

Here, variable1 is the name of the variable to be locked by a thread. The statements to be executed after placing a lock on variable1 are enclosed in curly braces following the lock statement. The lock statement locks the variable so that no other thread can access it for the time the lock is placed on the variable. To do this, the lock statement places an object known as mutual exclusion lock or mutex on the variable. No other thread is given access to a variable for the time mutex is placed on the variable.

Therefore, if thread1 places a lock or mutex on variable1, the operating system puts thread2 on sleep for the time mutex is placed on variable1.

By now, you know that synchronization is essential to prevent bugs in your multithreaded application. However, excessive synchronization might reduce the performance of your application. Now, look at the problems associated with the use of excessive synchronization.

When you place a lock on an object, no other thread is allowed to access this object. Therefore, any other thread that needs access to this object waits for the other thread to release the lock. If there are several threads waiting for the thread to release the lock, the overall performance of the application is affected. The performance of the application can be balanced to some extent by placing locks effectively. The lock on the object is placed for the time the compiler executes the statements in the lock block. Therefore, if you write minimum code in the lock statement, you can minimize the effect of placing a lock on a variable by an application.