Você está na página 1de 12

Osman Khalid, Lecturer, Computer Sciences Department, COMSATS Institute of Information Technology

Lecture (30 Dec)

Threading and Synchronization


Introduction Single processors and mutiprocessors Single core and due core processors

One nice feature of exceptions is that you can nest try blocks inside each other, like this: For all activities that require a wait for example, because of a file, database, or network access a new thread can be started to fulfill other tasks at the same time. Even if you have only processing - intensive tasks to do, threading can help. Multiple threads of a single process can run on different CPUs, or, nowadays, on different cores of a multiple - core CPU, at the same time. You must be aware of some issues when running multiple threads, however. Because they can run during the same time, you can easily get into problems if the threads access the same data. You must implement synchronization mechanisms. Semaphores, Mutexes

Overview A thread is an independent stream of instructions in a program. All your C# programs up to this point have one entry point the Main() method. Execution starts with the first statement in the Main() method and continues until that method returns. This program structure is all very well for programs, in which there is one identifiable sequence of tasks, but often a program needs to do more than one thing at the same time. Threads are important both for client - side and for server - side applications. While you type C# code in the Visual Studio editor, the Dynamic Help window immediately shows the topics that fit to the code you type. A background thread is searching through help. The same thing is done by the spell checker in Microsoft Word. One thread is waiting for input from the user, while the other does some background research. A third thread can store the written data in an interim file, while another one downloads some additional data from the Internet.

Downloaded from: www.onspot.pk

Osman Khalid, Lecturer, Computer Sciences Department, COMSATS Institute of Information Technology

In an application that is running on the server, one thread, the listener thread, waits for a request from a client. As soon as the request comes in, the request is forwarded to a separate worker thread, which continues the communication with the client. The listener thread immediately comes back to get the next request from the next client. With the Windows Task Manager, you can turn on the column Threads from the menu View Select Columns and see the processes and the number of threads for every process. Only cmd.exe is running inside a single thread; all the other applications shown in Figure use multiple threads. You can see one instance of Internet Explorer running 51 threads.

A process contains resources, such as Window handles, handles to the file system, or other kernel objects. Every process has virtual memory allocated. A process contains at least one thread.

Downloaded from: www.onspot.pk

Osman Khalid, Lecturer, Computer Sciences Department, COMSATS Institute of Information Technology

The operating system schedules threads. A thread has a priority, a program counter for the program location where it is actually processing, and a stack to store its local variables. Every thread has its own stack, but the memory for the program code and the heap are shared among all threads of a single process. This makes communication among threads of one process fast the same virtual memory is addressed by all threads of a process. However, this also makes things difficult because multiple threads can change the same memory location. With .NET, a managed thread is defined by the Thread class.

The Thread Class The code here is a very simple example of creating and starting a new thread. The constructor of the Thread class accepts a delegate parameter of type ThreadStart and ParameterizedThreadStart . The ThreadStart delegate defines a method with a void return type and without arguments. After the Thread object is created, you can start the thread with the Start() method:
using System; using System.Threading; namespace Wrox.ProCSharp.Threading { class Program { static void Main() { Thread t1 = new Thread(ThreadMain); t1.Start(); Console.WriteLine(This is the main thread.); } static void ThreadMain() { Console.WriteLine(Running in a thread.); } } } When you run the application, you get the output of the two threads: This is the main thread. Running in a thread.

Downloaded from: www.onspot.pk

Osman Khalid, Lecturer, Computer Sciences Department, COMSATS Institute of Information Technology

There is no guarantee as to what output comes first. Threads are scheduled by the operating system; which thread comes first can be different each time.

EXAMPLE: using System; using System.Threading; namespace Practice { /// <summary> /// Summary description for Class1. /// </summary> class Class1 { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main(string[] args) { // // TODO: Add code to start application here // Thread thread1 = new Thread(new ThreadStart(ThreadFunction1));

Console.WriteLine("first"); Console.WriteLine("second"); Console.WriteLine("third"); thread1.Start(); Console.WriteLine("fourth"); Console.WriteLine("fifth"); Console.WriteLine("sixth"); } static void ThreadFunction1() { Thread thread2 = new Thread(new ThreadStart(ThreadFunction2)); for(int i=0; i<5; i++) { Console.WriteLine("Executing first thread"); } thread2.Start(); } static void ThreadFunction2() { for(int i=0; i<5; i++) { Console.WriteLine("Executing second thread");

Downloaded from: www.onspot.pk

Osman Khalid, Lecturer, Computer Sciences Department, COMSATS Institute of Information Technology

} } } }

first second third Executing first thread Executing first thread Executing first thread Executing first thread Executing first thread fourth fifth sixth Executing second thread Executing second thread Executing second thread Executing second thread Executing second thread Press any key to continue . . .

Passing Data to Threads With the constructor of the Thread class, you can assign the new entry point ThreadMainWithParameters and invoke the Start() method passing the variable d :
public struct Data { public string Message; } static void Main() { Data d = new Data(); d.Message = Info; Thread t2 = new Thread(ThreadMainWithParameters); t2.Start(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 class:
public class MyThread { private string data; public MyThread(string data) { this.data = data;

Downloaded from: www.onspot.pk

Osman Khalid, Lecturer, Computer Sciences Department, COMSATS Institute of Information Technology

} public void ThreadMain() { Console.WriteLine(Running in a thread, data: {0}, data); } }

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. MyThread obj = new MyThread(info); Thread t3 = new Thread(obj.ThreadMain); t3.Start();

EXAMPLE:
using System; using System.Threading; namespace T { public class Multiply { public Thread mythread; string name; int counter; public Multiply(string s, int c) { name = s; counter = c; mythread = new Thread(new ThreadStart(start)); //ThreadStart del_thread = new ThreadStart(start); //mythread = new Thread(del_thread); } public void start() { Console.WriteLine(" Now thread " + name + " started"); for(int i=0; i<=counter; i++) { if(i % counter == 0) Console.WriteLine(name + " of i " + i); } Console.WriteLine(" Thread " + name + " finished\n"); }

Downloaded from: www.onspot.pk

Osman Khalid, Lecturer, Computer Sciences Department, COMSATS Institute of Information Technology

public class Test { static int counter; static void Main() { counter = 1000; Multiply m1 = new Multiply("first",counter); Multiply m2 = new Multiply("second",counter); m1.mythread.Start(); m2.mythread.Start(); } } } }

Now thread first started first of i 0 first of i 1000 Thread first finished Now thread second started second of i 0 second of i 1000 Thread second finished Press any key to continue . . .

EXAMPLE
using System; using System.Threading; namespace Practice { class TestClass { public Thread UserThread; string threadname; int number; public TestClass(string tname, int num) { threadname = tname; number = num; UserThread = new Thread(new ThreadStart(threadfunction)); } public void threadfunction() {

Downloaded from: www.onspot.pk

Osman Khalid, Lecturer, Computer Sciences Department, COMSATS Institute of Information Technology

Console.WriteLine("A thread function is being called"); } } class MainClass { static void Main() { TestClass t = new TestClass("first",10); t.UserThread.Start(); Console.WriteLine("This is main"); } } }

This is main A thread function is being called Press any key to continue . . .

Background Threads 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. 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 IsBackground property of the thread t1 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.
class Program { static void Main()

Downloaded from: www.onspot.pk

Osman Khalid, Lecturer, Computer Sciences Department, COMSATS Institute of Information Technology

{ Thread t1 = new Thread(ThreadMain); t1.Name = MyNewThread1; t1.IsBackground = false; t1.Start(); Console.WriteLine(Main thread ending now...); } static void ThreadMain() { Console.WriteLine(Thread {0} started, Thread.CurrentThread.Name); Thread.Sleep(3000); Console.WriteLine(Thread {0} completed, Thread.CurrentThread.Name); } }

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. Main thread ending now... Thread MyNewThread1 started Thread MyNewThread1 completed If you change the IsBackground property to start the new thread to true , the result shown at the console is different. Main thread ending now... Thread MyNewThread1 started 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 checkerthread 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.

Thread Priority You have learned that the operating system schedules threads. You have had a chance to influence the scheduling by assigning a priority to the thread. With the Thread class, you can influence the base priority of the thread by setting the Priority property.

Downloaded from: www.onspot.pk

Osman Khalid, Lecturer, Computer Sciences Department, COMSATS Institute of Information Technology

The Priority property requires a value that is defined by the ThreadPriority enumeration. The levels defined are Highest , AboveNormal , Normal , BelowNormal , and Lowest .

EXAMPLE:
using System; using System.Threading; namespace Practice { class Class1 { static void Main(string[] args) { // // TODO: Add code to start application here //

Thread t1 = new Thread(new ThreadStart(first)); Thread t2 = new Thread(new ThreadStart(second)); Thread t3 = new Thread(new ThreadStart(third)); Console.WriteLine("Main Console.WriteLine("Main Console.WriteLine("Main Console.WriteLine("Main thread thread thread thread is is is is running running running running 1"); 2"); 3"); 4");

t1.Priority = ThreadPriority.Lowest; Console.WriteLine("Main Console.WriteLine("Main Console.WriteLine("Main Console.WriteLine("Main thread thread thread thread is is is is running running running running 5"); 6"); 7"); 8");

t2.Priority = ThreadPriority.BelowNormal; Console.WriteLine("Main Console.WriteLine("Main Console.WriteLine("Main Console.WriteLine("Main thread thread thread thread is is is is running running running running 9"); 10"); 11"); 12");

t3.Priority = ThreadPriority.Highest; t1.Start(); t2.Start(); t3.Start();

Console.WriteLine("Main thread is running 13"); Console.WriteLine("Main thread is running 14");

Downloaded from: www.onspot.pk

Osman Khalid, Lecturer, Computer Sciences Department, COMSATS Institute of Information Technology

Console.WriteLine("Main thread is running 15"); Console.WriteLine("Main thread is running 16"); } static void first() { Console.WriteLine("First function - called by lowest priority thread"); } static void second() { Console.WriteLine("Second function - called by below normal priority thread"); } static void third() { Console.WriteLine("third function - called by highest priority thread"); } } }

Main thread is running 1 Main thread is running 2 Main thread is running 3 Main thread is running 4 Main thread is running 5 Main thread is running 6 Main thread is running 7 Main thread is running 8 Main thread is running 9 Main thread is running 10 Main thread is running 11 Main thread is running 12 First function - called by lowest priority thread Second function - called by below normal priority thread Main thread is running 13 Main thread is running 14 Main thread is running 15 Main thread is running 16 third function - called by highest priority thread Press any key to continue . . .

Controlling Threads Thread.ThreadState 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.

Downloaded from: www.onspot.pk

Osman Khalid, Lecturer, Computer Sciences Department, COMSATS Institute of Information Technology

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.ThreadState . Thread.Sleep() With the Thread.Sleep() method, a thread goes into the WaitSleepJoin state and waits until it is woken up again after the time span defined with the Sleep() method has elapsed.

Thread.Abort() To stop another thread, you can invoke the method Thread.Abort() . When this method is called, an exception of type ThreadAbortException 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. Thread.ResetAbort() 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 AbortRequested to the Aborted state if the thread does not reset the abort. Thread.Join() 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 WaitSleepJoin state until the thread that is joined is completed.

Race Condition A race condition can occur if two or more threads access the same objects and access to the shared state is not synchronized. Deadlock Too much locking can get you in trouble as well. In a deadlock, at least two threads halt and wait for each other to release a lock. As both threads wait for each other, a deadlock occurs and the threads wait endlessly.

Downloaded from: www.onspot.pk

Você também pode gostar