Click here to Skip to main content
15,878,852 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hi Everyone,
I'm a student who is creating a basic multi-threading program. It has two threads, each running simple loops. One is counting up from 0 to 10 and the other from 10 to 0.
All I am after is get the program to know when both threads get to the same number, I know it will be five (or at least should be) but I don't know how to pull out this data each time so that it can be checked. I've tried using return but this obviously exits the loop and therefore will only run each loop one iteration. Below is the code I currently have.

Thanks for any help or advice.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            object iValue = 0;
            object iValue2 = 10;
            Thread th = new Thread(delegate() {
                ThreadFunction(iValue);
            });

            Thread th2 = new Thread(delegate()
            {
                ThreadFunction2(iValue2);
            });
            th.Start();
            th2.Start();
            if (th.ThreadState == ThreadState.Stopped && th2.ThreadState == ThreadState.Stopped)
            Console.WriteLine("The two numbers are identical: " + iValue.ToString() + " and " + iValue2.ToString());
        }
        static object ThreadFunction(object iV)
        {
            for (int i = 0; i < 10; i++)
            {
                    int iValueLocal = (int)iV;
                    Thread.Sleep(1000);
                    iValueLocal++;
                    iV = iValueLocal;
                  
            }
            object iB = (object)iV;
            return iB;
        }

        static object ThreadFunction2(object iV)
        {
            for (int i = 10; i > 0; i--)
            {
                int iValueLocal = (int)iV;
                Thread.Sleep(1000);
                iValueLocal--;
                iV = iValueLocal;
            }
            object iB = (object)iV;
            return iB;
        }
    }
}
Posted

look at each thread that you are running.

Ask yourself: do I see any logic that will stop the thread when iValue == iValue2?

Also ask yourself: what happens in my code if the threads start, they have not stopped and my if statement is false?

You need to figure out a way for your main program to continue looping while the threads have not stopped.

I hope this puts you in the proper direction for debugging your code.
 
Share this answer
 
v2
Comments
pows1_09 14-Apr-12 7:33am    
I appreciate the comment, however the values never change and therefore the program stops straight away if I put in this statement.
It looks like the purpose of your code is to demonstrate the effect of race condition :-). Am I right?

No matter, there is nothing wrong the idea of data exchange with a running thread; and knowing good techniques for that is very important.

My approach is working with the threads created through thread constructors is hiding both thread object and thread method in a thread wrapper. This techniques has more then one benefit. First of all, the thread method cam be an instance method (that is, non-static method) of the wrapper. This is the way to avoid ugly parametrized thread start, which is always bad because it requires a type case. With wrapper and an instance method, this is never needed because an the call to the instance method passes "this", a target reference as an implicit first parameter. In case of thread and a thread wrapper, this is the only parameter (as required by the thread constructor) and a reference to the instance of the wrapper. This way, the thread body gets access to all of the members of the wrapper class at once.

More than that, it helps to encapsulate the data accessible by both the wrapped thread and other threads. Making some members private guarantees that the data is used only in a wrapped thread. Other members can be done internal/private and used by more then one thread. If is advisable to provide such access only to the methods and properties. This way, access to the shared data can be synchronized with some thread synchronization primitives, such as lock statement, System.Threading.EventWaitHandle, System.Threading.ReaderWriterLockSlim, System.Threading.Monitor and the like — please see:
http://msdn.microsoft.com/en-us/library/c5kehkcz%28v=vs.100%29.aspx[^],
http://msdn.microsoft.com/en-us/library/system.threading.eventwaithandle.aspx[^],
http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx[^],
http://msdn.microsoft.com/en-us/library/system.threading.monitor.aspx[^].

What is really important, the use of the thread synchronization objects is hidden inside the wrapper; the objects cannot be misused by the code using the wrapper. Such misuse is a usual problem, so this is yet another considerable benefit.

For a sample code of a thread wrapper, please see my past answers:
How to pass ref parameter to the thread[^],
change paramters of thread (producer) after it started[^].

The code sample in the second answer demonstrates the use of lock statement.

—SA
 
Share this answer
 
Comments
pows1_09 14-Apr-12 5:18am    
Thanks for the reply, this seems very useful and your code used on:
http://www.codeproject.com/Answers/155852/How-to-pass-ref-parameter-to-the-thread#answer2
looks good, I seem to understand the logic but why is it internal?
The reason I ask is because I've created a new class called ThreadWrapper which I made internal, and added your code to it, but it comes up with lots of errors. Is the class already created? and rather than doing all the internal bits, is it just possible to do a get and set method within my code as currently I am not aiming for efficiency or organisation, purely something that works.
Sergey Alexandrovich Kryukov 20-Apr-12 16:49pm    
It is internal because it's the best to give minimum access, in order to avoid programming mistakes. Internal, as you need to know, only limits access to the same assembly, in all other respects it is exactly the same as public. In this case, I consider it reasonable: you can have different wrappers for different assemblies. If you want to re-use some wrapper across assemblies, make it public, make Body "protected abstract" and override in descendant classes.
--SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900