Personal notes on software development.
For Java technologies check my dedicated site

Pages

The System.Threading namespace provides a wealth of classes and interfaces to manage multi-threaded programming;


Creating Threads:

The simplest way to create a thread is to create a new instance of the Thread class.
The Thread constructor takes a single argument: a delegate instance. The CLR provides the ThreadStart delegate class specifically for this purpose, which points to a method you designate. This allows you to construct a thread and to say to it, “When you start, run this method.”
The ThreadStart delegate declaration is:
public delegate void ThreadStart( );
As you can see, the method you attach to this delegate must take no parameters and must return void. Thus, you might create a new thread like this:
Thread myThread = new Thread( new ThreadStart(myFunc) );
myThread.Start( ); //starts thread execution
Where myFunc looks like (returns void and takes no parameters):
public void myFunc(){
    (...)
}


Waiting for other threads to finish execution

This can be acomplished by calling:
myThread.Join( );

Example if you have a list of threads and the current thread needs to wait till they finish execution:
foreach (Thread myThread in myThreads)
{
    myThread.Join( );
}
Console.WriteLine("All my threads are done.");


Halting thread execution

Thread.Sleep(100); //halts execution for 100 milliseconds
/* NOTE:the zero value is a special case that signals the thread scheduler that you’d like your thread to yield to another thread, even if the thread scheduler might otherwise give your thread a bit more time: */
Thread.Sleep(0); 


Killing a thread

Typically, threads die after running their course but there are multiple ways to force stop a thread:
  • You can ask a thread to kill itself. The cleanest way is to set a KeepAlive Boolean flag that the thread can check periodically. When the flag changes state (e.g., goes from true to false), the thread can stop itself;
  • an alternative is to call Thread.Interrupt, which asks the thread to kill itself;
  • in desperation, and if you are shutting down your application in any case, you may
    call Thread.Abort. This causes a ThreadAbortException exception to be thrown, which
    the thread can catch.

Synchronizing threads

Synchronization is provided by a lock on the object, which helps the developer avoid having a second thread barge in on your object until the first thread is finished with it.

The CLR provides a number of synchronization mechanisms. These include the common synchronization tools such as critical sections (called locks in .NET), as well as the Monitor class:
  • Interlocked class: is a special class only usefull to increment/decrement variables in a synchronized manner.
    int temp = Interlocked.Increment(ref counter);
    These methods have some overloads making it possible to operate with int, floats, etc.

  • The C# lock keyword is a more general synchronization mechanism.
    A lock marks a critical section of your code, providing synchronization to an object you designate while the lock is in effect.
    Example (calling this inside an object, the "counter" variable simulates a shared resource):
    int temp;
    lock (this)
    {
        temp = counter;
        temp++;
        Thread.Sleep(1); //no problem no other thread will achieve
                         //the resource till the block is over
        counter = temp;
    }
    Console.WriteLine("Thread {0}. Incrementer: {1}", Thread.CurrentThread.Name, temp);
    

    Example2:
    class Program
    {
        private int counter;
        static void Main(string[] args)
        {
            Program p = new Program();
            Thread t1 = new Thread(new ThreadStart(p.Increment));
            t1.Name = "t1";
            Thread t2 = new Thread(new ThreadStart(p.Increment));
            t2.Name = "t2";
            t1.Start();
            t2.Start();
            Console.WriteLine("Main thread finished execution");
            Console.ReadKey();           
        }
    
    
        private void Increment()
        {
            int temp;
            for (int i = 0; i < 5; i++)
            {
                lock(this){
                    temp = counter;
                    temp++;
                    Thread.Sleep(0);
                    counter = temp;
                }
                Console.WriteLine("{0}:{1}",Thread.CurrentThread.Name, counter);
                Thread.Sleep(0);
            }
            Console.WriteLine("Thread {0} finished execution", Thread.CurrentThread.Name);
        }
    }
    
    /*OUTPUT:
    Main thread finished execution
    t1:1
    t2:2
    t1:3
    t2:4
    t1:5
    t2:6
    t1:7
    t2:8
    t1:9
    Thread t1 finished execution
    t2:10
    Thread t2 finished execution
    */
    Note: the inner "Thread.Sleep(0)" wont do nothing since the other thread is waiting for the locked resource. The outer "Thread.Sleep(0)" is making the Threads achieve the resource in an alternate way;

No comments:

Post a Comment