I have a Lottery class in C#. It consists of an async method that may be called from an event handler (such as button click in a windows form). This async method calls a normal method that creates 4 threads. Each thread plays the lottery about 10000000 times. Right before they have finished, the threads calculate the average hit count per draw and write this back to a shared float array. The float array has as many slots as the number of threads created (i.e. 4 slots). Thread 0 locks the array object and writes the result to slot 0, Thread 1 to slot 1 and so on.
If I choose small numbers for the loop times (1000 instead of 10000000) everything works fine. But if I choose large numbers, the threads sometimes will not finish. They sometimes do not even reach the end of their methods.
I cannot figure out why.
class Lottery
{
float[] results;
Thread[] threads;
Random r;
public async Task<float[]> playAsync(int pCores)
{
return await Task.Run(() => play(pCores));
}
private float[] play(int pCores)
{
r = new Random();
results = new float[pCores];
threads = new Thread[pCores];
for (int i = 0; i < pCores; i++)
{
Thread newThread = new Thread(new ParameterizedThreadStart(playLottery));
threads[i] = newThread;
long[] threadData = new long[] { 10000000, i };
newThread.Start(threadData);
}
for (int i = 0; i < pCores; i++)
{
threads[i].Join();
}
return results;
}
private void playLottery(object pThreadData)
{
long[] threadData = (long[])pThreadData;
long pTimes = threadData[0];
long resultSlot = threadData[1];
int[] numbers = new int[6];
int[] numbersDrawn = new int[6];
int numbersTaken = 0;
long timeCounter = 0;
while(numbersTaken < 6)
{
lock(r)
{
int cNumber = r.Next(1, 50);
if (!numbers.Contains(cNumber))
{
numbers[numbersTaken] = cNumber;
numbersTaken++;
}
}
}
float hitsPerGame = 0;
long totalHits = 0;
while(timeCounter < pTimes)
{
int hits = 0;
int numbersDrawnTaken = 0;
numbersDrawn = new int[numbers.Length];
// Actual draw:
while (numbersDrawnTaken < 6)
{
lock (r)
{
int cNumber = r.Next(1, 50);
if (!numbersDrawn.Contains(cNumber))
{
numbersDrawn[numbersDrawnTaken] = cNumber;
numbersDrawnTaken++;
}
}
}
//compare chosen with drawn numbers
for(int i = 0; i < numbers.Length; i++)
{
for(int j = 0; j < numbers.Length; j++)
{
if(numbers[i] == numbersDrawn[j])
{
hits++;
}
}
}
totalHits += hits;
timeCounter++;
}
hitsPerGame = totalHits / (float)pTimes;
Console.WriteLine("Hitrate Thread " + resultSlot + ": " + hitsPerGame);
lock (results)
{
results[resultSlot] = hitsPerGame;
}
}
}
numbers[] contains 6 numbers chosen by the human (simulated by random numbers in this example). numbersDrawn[] calculates 6 numbers each loop and compares those numbers to the numbers in numbers[].
Aucun commentaire:
Enregistrer un commentaire