Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Consequence of running multiple concurrent threads?

I've been hitting my head with this for the past few hours, so here goes. Maybe it's a common mistake for someone with little experience with multi-threading? Who knows.

In the included code I instantiate 3 threads that run method DisplayValues(DateTime Now, int Period). The debugger stops three times in each of the if statements and, for each, it does the method call with correct values. The problem is that Console.WriteLine is displaying erratic values, completely different to how the calls were made.

The console calls DisplayValues() 3 times with the following parameters, which is correct: DisplayValues('{5/8/2014 4:20:00 AM}', 0); DisplayValues('{5/8/2014 4:35:00 AM}', 1); DisplayValues('{5/8/2014 4:50:00 AM}', 2);

But the output is completely different:

5/8/2014 4:35:00 AM Period: 0

5/8/2014 4:50:00 AM Period: 1

5/8/2014 4:51:00 AM Period: 2

The debugger confirms this. Since it's a console application, I thought it could be that all methods were static, so I moved DisplayValues() to a class. Then I thought that all three class instances had the same name, so I changed the name. Then I thought it could be the CancellationTokenSource object, so I removed that also.

Needless to say, without the threads the output is correct.

I know there's an obvious reason, I just don't know what it is.

Any help is appreciated. Thanks.

bool thread0Running = false;
bool thread1Running = false;
bool thread2Running = false;
DateTime DateNow = new DateTime(2014, 5, 8, 4, 0, 0);

while ((!thread0Running || !thread1Running || !thread2Running) && DateNow.Hour == 4)
{
    if ((DateNow.Hour == TaskDateTime.Hour) && (DateNow.Minute == 20))
    {
        thread0Running = true;
        Class myClass0 = new Class();
        new Thread(() => myClass0.DisplayValues(DateNow, 0, cts0.Token)).Start();

    }
    else if ((DateNow.Hour == TaskDateTime.Hour) && (DateNow.Minute == 35))
    {
        thread1Running = true;
        Class myClass1 = new Class();
        new Thread(() => myClass1.DisplayValues(DateNow, 1, cts1.Token)).Start(); 
    }
    else if ((DateNow.Hour == TaskDateTime.Hour) && (DateNow.Minute == 50))
    {
        thread2Running = true;
        Class myClass2 = new Class();
        new Thread(() => myClass2.DisplayValues(DateNow, 2, cts2.Token)).Start();
    }
    DateNow = DateNow.AddMinutes(1);
}
public void DisplayValues(DateTime Now, int Period, Object obj)
{
        Console.WriteLine(Now.ToString() + " Period: " + Period.ToString());
}
like image 985
Joe_Hendricks Avatar asked May 08 '14 21:05

Joe_Hendricks


1 Answers

Thread.Start doesn't mean the thread starts running immediately, it Causes the operating system to change the state of the current instance to ThreadState.Running. Once a thread is in the ThreadState.Running state, the operating system can schedule it for execution, but it doesn't means the thread created first will be executed first. This is the reason of the problem.

If you want to make the 3 thread running in sequence, you should look into thread synchronization.

like image 193
Matt Avatar answered Oct 08 '22 06:10

Matt