Click here to Skip to main content
Email Password   helpLost your password?

Sample Image - easythread.jpg

Introduction

Threads are a powerful abstraction for allowing parallelized operations: graphical updates can happen while another thread is performing computations, two threads can handle two simultaneous network requests from a single process, and the list goes on. Since threads are pretty simple to understand, conceptually, but, practically, they are a cause for programmatic headaches, I decided to write this program to describe how to make use of threads.

Background

To understand this code completely, you need to have some basics on C# language. I used some forms and controls that are easy to understand. You can refer to the MS Visual Studio documentation to understand the System.Threading.Thread class and all its properties and methods.

Using the code

The project AutoChess.sln consists of three classes:

  1. Form1.cs
  2. King.cs
  3. Soldier.cs

This program, when executed, shows the previous grid. If one presses the (Start) button, those pieces start to move in random fashion. The King moves in any direction and the soldiers move in diagonals. Let's have a closer look at the code. We declared four threads, one for each piece:

Thread t1, t2, t3, t4;

Then, we create our four threads:

t1 = new Thread(ThreadStart(MoveWhiteKing)); 
t2 = new Thread(ThreadStart(MoveBlackKing)); 
t3 = new Thread(ThreadStart(MoveWhiteSoldier));
t4 = new Thread(ThreadStart(MoveBlackSoldier));

where MoveWhiteKing, MoveBlackKing,... are delegates that refer to methods responsible for moving the pieces. And I decided also to create an object for each piece used. Those are:

WK = new WindowsApplication1.King (bs, WhiteKingPic, WhiteSoldierPic);
BK = new WindowsApplication1.King (bs, BlackKingPic, BlackSoldierPic);
WS = new WindowsApplication1.King (bs, WhiteSoldierPic, 
                              WhiteKingPic, BlackKingPic);
BS = new WindowsApplication1.King (bs, BlackSoldierPic, 
                              BlackKingPic, WhiteKingPic);

To start the four threads, the following code is put in button1_Click(), which is the Start button:

private void button1_Click(object sender, System.EventArgs e)
{
    this.button1.Enabled = false;
    t1.Start();
    t2.Start();
    t3.Start();
    t4.Start();
}

To understand more on how each thread works, let's have a closer look at the method referenced by the delegates. Let's take the MoveWhiteKing() as an example:

private void MoveWhiteKing ()
{
    lock( synchronizeVariable ) 
    {
        while(true)
        {
            Thread.Sleep(1000);
            Monitor.PulseAll( synchronizeVariable );
            WK.MoveKing(bs);
            Monitor.Wait( synchronizeVariable );
        }
    }
}

We use the synchronizeVariable object that is assigned in the beginning of the program:

public static Object synchronizeVariable = "locking variable";

This variable is used to guarantee a certain behavior so that no two pieces move together. This is possible since there is only one thread that can grab the synchronizeVariable and, in turn, can be active at a time. Thread.Sleep(1000) causes the thread to be delayed by one second, and then the thread notifies all other threads that the synchronizeVariable is with it and no thread can take the control. The thread calls the method for moving the piece according to some defined rules. Then, the current thread puts itself into a Wait(), releasing the variable to allow other threads to grab it, and so on.

Conclusion

I hope this example will be useful for many. I noticed that there are few examples discussing threads, especially those with the synchronization characteristic. So, I tried to make this example as easy as possible to understand. I will feel glad if there is anyone who wants to make suggestions or discuss on anything that I can help in.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
Generalnice
Sameh Ahmed
12:44 27 Dec '02  
nice ahmed.
good sample ...

May be there are millions better than me but they are not me
GeneralRe: nice
Anonymous
21:36 31 Dec '02  
Thnx Wink
GeneralIntent of this example?
Burt Harris
7:37 7 Dec '02  
Hi Ahmad,

It seems to me like there is a mismatch betwen the game sample you've provided and the way you are using locks. For example, I think it would be possible for your threads could get out-of-syncronization, and one side could take two turns in a row.

I'm not sure which your intent is. Do you want good code to implement this game, or were you searching for a graphical illustration of locking.

Burt Harris
GeneralsynchronizeVariable
Burt Harris
7:31 7 Dec '02  
With your current approach, synchronizeVariable is a public static. This is a little dangerous. The Monitor class overview says "When selecting an object on which to synchronize, you should lock only on private or internal objects. Locking on external objects might result in deadlocks, because unrelated code could choose the same objects to lock on for different purposes."

Admitily, with your simple example, this is unlikely to occur. You could, and probably should, make the variable private static. I'd do it this way:

private static Object synchronizeVariable = new Object();

Burt Harris
GeneralNot very wise
Carsten Breum
0:18 4 Dec '02  
Hi,

There are more mistakes in your code. First, your lock all but one thread, so what’s the point in having multiple threads? Second, in the while loop you start sleeping for 1 sec. This actually saves you when you next call PulseAll. The reason for that is that you operate directly on a variable, the buttons, from the main GUI thread. If you where running the application on a machine with multiple processors and you did not call sleep then you could end with two threads working directly on the buttons at the same time. The outcome of that is not predictable. So all in all this is not a very wise design. Instead you should call invoke on a delegate function in the main GUI thread from your worker threads. I would not at all use sleep but something like WaitHandle instead.


Regards,
Carsten
GeneralRe: Not very wise
Ahmad Al-Kayali
15:06 4 Dec '02  
Thank you Carsten for the points that you raised. First, you mentioned (you lock all but one thread). Actually, I am using mutithreads here to serialize the movement of the pieces. You can notice that if you run the program and see the pattern of movemen.If I dont use the (lock) then, i will not be able to make them move in serial, rather, they will just move in parallel and this is not the requirement. The second case that you mentioned will not happen, since I am using the (lock) that protects all threads but one to be the working thread.
Thank you for sharing your commets.

Regards,
Ahmad,


Last Updated 1 Dec 2002 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010