Próbuję napisać aplikację, która dzieli zadanie obliczeniowe na 4 części i uruchamia je w 4 wątkach, potem przechodzi dalej po skończeniu tych 4 wątków.
Jak czytałem w Google, jak uruchomić wątek z parametrem, to trafiłem na postać new Thread(() => ThrProc(i))
. Z tym wiąże się jeden problem.
Problem polega na tym, że obiekt typu Thread zostaje utworzony w momencie, gdy zmienna i ma pewną wartość, ale jak wątek wystartuje przy następnej iteracji pętli lub po jej skończeniu, to zmiana zmiennej pętli powoduje zmianę parametru funkcji. Z czego to może wynikać? Przecież w danym momencie zmienna i ma określoną wartość i z taką wartością tworzę obiekt, a potem uruchamiam wątek. Co ma stan zmiennej pętli do obiektu wątku, który został już zbudowany, tym bardziej, że zmienną przekazuje się przez wartość, a nie przez referencję.
A jak się zadeklaruje dodatkową zmienną i do nie przypisze parametr, to tego problemu już nie ma. A może nadal jest, tylko prawdopodobieństwo jego wystąpienia jest marginalne i nie miałem przypadku, żeby problem wystąpił (bo jednak dokończenie iteracji pętli, inkrementacja iteratora, sprawdzenie warunku zakończenia i rozpoczęcie nowej iteracji trochę trwa, dopiero potem dodatkowa zmienna dostaje nową wartość)?
Czy powyższy sposób i sposób z ParameterizedThreadStart
są równoważne?
Jak widać, są 4 warianty tego samego.
Wariant 1: W nim następuje zmiana argumentu po podaniu do funkcji
Wariant 2: Dodatkowa zmienna rozwiązuje problem w wariancie 1
Wariant 3: Inny sposób uruchamiania wątku z parametrem (znaleziony później za pomocą google), nie ma problemu występującego w wariancie 1.
Wariant 4: Sposób taki, jak w wariancie 3, przekazywana zmienna typu obiekt
jest zmienną zmienianą w pętli (chodziło o to, żeby nie następowała zmiana z int do object przy przekazywaniu do funkcji), tu problem nie występuje.
using System;
using System.Diagnostics;
using System.Threading;
namespace TestThr
{
class ObjX
{
Thread[] Thr;
int ThrNum = 4;
int[][] TestData;
// Wartosc dobrana doświadczanie, aby wątek trwał kilka sekund
int TestLen = 100000000;
void ThrProcObj(object N)
{
ThrProc((int)N);
}
void ThrProc(int N)
{
Stopwatch SW = new Stopwatch();
SW.Start();
Console.WriteLine("Thread " + N + " start");
if (N < ThrNum)
{
// Jakieś przypadkowe obliczenia mające zająć czas procesorowi
for (int i = 0; i < TestLen; i++)
{
TestData[N][i + 2] = (TestData[N][i] + TestData[N][i + 1]) % 1000;
}
for (int i = 0; i < TestLen; i++)
{
TestData[N][i] = (TestData[N][i] * 27) % 1000;
}
}
Console.WriteLine("Thread " + N + " stop " + SW.ElapsedMilliseconds);
}
public void Start()
{
Thr = new Thread[ThrNum];
TestData = new int[ThrNum][];
Random TestR = new Random();
for (int i = 0; i < ThrNum; i++)
{
TestData[i] = new int[TestLen + 2];
TestData[i][0] = TestR.Next(1000);
TestData[i][1] = TestR.Next(1000);
}
Stopwatch SWX = new Stopwatch();
Console.WriteLine("Multi thread 1 start");
SWX.Reset();
SWX.Start();
for (int i = 0; i < ThrNum; i++)
{
Thr[i] = new Thread(() => ThrProc(i));
Thr[i].Start();
}
for (int i = 0; i < ThrNum; i++)
{
Thr[i].Join();
}
SWX.Stop();
Console.WriteLine("Multi thread 1 stop " + SWX.ElapsedMilliseconds);
Console.WriteLine("Multi thread 2 start");
SWX.Reset();
SWX.Start();
for (int i = 0; i < ThrNum; i++)
{
int i_ = i;
Thr[i] = new Thread(() => ThrProc(i_));
Thr[i].Start();
}
for (int i = 0; i < ThrNum; i++)
{
Thr[i].Join();
}
SWX.Stop();
Console.WriteLine("Multi thread 2 stop " + SWX.ElapsedMilliseconds);
Console.WriteLine("Multi thread 3 start");
SWX.Reset();
SWX.Start();
for (int i = 0; i < ThrNum; i++)
{
Thr[i] = new Thread(new ParameterizedThreadStart(ThrProcObj));
Thr[i].Start(i);
}
for (int i = 0; i < ThrNum; i++)
{
Thr[i].Join();
}
SWX.Stop();
Console.WriteLine("Multi thread 3 stop " + SWX.ElapsedMilliseconds);
Console.WriteLine("Multi thread 4 start");
SWX.Reset();
SWX.Start();
object i_obj = 0;
for (int i = 0; i < ThrNum; i++)
{
Thr[i] = new Thread(new ParameterizedThreadStart(ThrProcObj));
Thr[i].Start(i_obj);
i_obj = ((int)i_obj) + 1;
}
for (int i = 0; i < ThrNum; i++)
{
Thr[i].Join();
}
SWX.Stop();
Console.WriteLine("Multi thread 4 stop " + SWX.ElapsedMilliseconds);
}
}
class MainClass
{
public static void Main(string[] args)
{
Console.WriteLine("START");
ObjX X = new ObjX();
X.Start();
Console.WriteLine("STOP");
}
}
}