C Sharp Programming/The .NET Framework/Threading

Threads are tasks that can run concurrently to other threads and can share data. When your program starts, it creates a thread for the entry point of your program, usually a function. So, you can think of a "program" as being made up of threads. The .NET Framework allows you to use threading in your programs to run code in parallel to each other. This is often done for two reasons:


 * 1) If the thread running your graphical user interface performs time-consuming work, your program may appear to be unresponsive. Using threading, you can create a new thread to perform tasks and report its progress to the GUI thread.
 * 2) On computers with more than one CPU or CPUs with more than one core, threads can maximize the use of computational resources, speeding up tasks.

The class
The class exposes basic functionality for using threads. To create a thread, you simply create an instance of the class with a  or   pointing to the code the thread should start running. For example:

You should see the following output:

Second thread says hello. First thread says hello. First thread says hello. Second thread says hello. First thread says hello. First thread says hello. ...

Notice that the keyword is needed because as soon as the function s, the thread exits, or terminates.

ParameterizedThreadStart
The delegate allows you to pass a parameter to the new thread:

The output is:

First thread says hello. Second thread says 1234. Second thread says 1234. First thread says hello. ...

Sharing Data
Although we could use to pass parameter(s) to threads, it is not typesafe and is clumsy to use. We could exploit anonymous delegates to share data between threads, however:

Notice how the body of the anonymous delegate can access the local variable.

Asynchronous Delegates
Using anonymous delegates can lead to a lot of syntax, confusion of scope, and lack of encapsulation. However with the use of lambda expressions, some of these problems can be mitigated. Instead of anonymous delegates, you can use asynchronous delegates to pass and return data, all of which is type safe. It should be noted that when you use an asynchronous delegate, you are actually queuing a new thread to the thread pool. Also, using asynchronous delegates forces you to use the asynchronous model.

Synchronization
In the sharing data example, you may have noticed that often, if not all of the time, you will get the following output:

First thread says 2. Second thread says 3. Second thread says 5. First thread says 4. Second thread says 7. First thread says 7.

One would expect that at least, the numbers would be printed in ascending order! This problem arises because of the fact that the two pieces of code are running at the same time. For example, it printed 3, 5, then 4. Let us examine what may have occurred:


 * 1) After "First thread says 2", the first thread incremented, making it 3, and printed it.
 * 2) The second thread then incremented, making it 4.
 * 3) Just before the second thread got a chance to print, the first thread incremented , making it 5, and printed it.
 * 4) The second thread then printed what  was before the first thread incremented it, that is, 4. Note that this may have occurred due to console output buffering.

The solution to this problem is to synchronize the two threads, making sure their code doesn't interleave like it did. C# supports this through the keyword. We can put blocks of code under this keyword:

The variable is needed because the  keyword only operates on reference types, not value types. This time, you will get the correct output:

First thread says 2. Second thread says 3. Second thread says 4. First thread says 5. Second thread says 6. ...

The keyword operates by trying to gain an exclusive lock on the object passed to it. It will only release the lock when the code block has finished execution (that is, after the ). If an object is already locked when another thread tries to gain a lock on the same object, the thread will block (suspend execution) until the lock is released, and then lock the object. This way, sections of code can be prevented from interleaving.

The method of the  class allows a thread to wait for another thread, optionally specifying a timeout:

The output is:

Just started second thread. Second thread reporting. First thread waited for 1 second. Second thread done sleeping. First thread finished waiting for second thread. Press any key.