I am attempting to model slot machine behavior with parallel programming, using a base class (SlotBase) which will be overridden by classes representing each individual machine.
In the base class, I have a method that (attempts to) invoke a descendant class's method (marked abstract in the base class) that plays a sample and returns results through use of output parameters, and then using a mutually exclusive lock, updates the base class's summation variables.
Relevant code samples as follows: From SlotBase.cs:
#region Member Variables
protected long m_CoinIn;
protected long[] m_CoinOut;
protected string[] m_FeatureList;
protected long[] m_HitCount;
// .. and many more, but redacted for length
#endregion
protected abstract void PlaySample(long sampleSize, out long coinIn, out long[] coinOut, out long[] hitCount);
protected override void DoSimulation() {
// No need to intialize these, as the calling routine will, and only it knows how big the arrays need to be, and so forth.
object mutex = new object();
if (ParallelMode) {
int periodCount = (int)(BatchSize / PeriodSize);
Parallel.For(0, periodCount, delegate(int i) {
long coinIn;
long[] coinOut;
long[] hitCount;
PlaySample(PeriodSize, out coinIn, out coinOut, out hitCount);
lock (mutex) {
Console.WriteLine("Coin in this batch: {0}", coinIn);
m_CoinIn += coinIn;
for (int j = 0; j < m_FeatureList.Length; ++j) {
m_CoinOut[j] += coinOut[j];
m_HitCount[j] += hitCount[j];
}
}
});
}
}
.. and from a typical subclass implementation:
protected override void PlaySample(long sampleSize, out long coinIn, out long[] coinOut, out long[] hitCount) {
switch (WagerIndex) {
case (int)WagerType.Main: {
RNG localRNG = SpawnRNG();
coinIn = 0;
coinOut = new long[m_FeatureList.Length];
hitCount = new long[m_FeatureList.Length];
for (long iter = 0; iter < sampleSize; ++iter) {
coinIn += m_LinesPlayed;
double[] output = GetSpinResults(ref localRNG, (int)SpinMode.MainSpin);
for (int i = 0; i < m_FeatureList.Length; ++i) {
coinOut[i] += (long)output[i];
if (output[i] > 0) ++hitCount[i];
}
}
break;
}
default: {
throw new Exception(string.Format("Wager Type index {0} not supported", WagerIndex));
}
}
}
.. this actually works quite effectively with small values of SampleSize and PeriodSize but quickly proceeds to hang (or virtually hang) as values increase.
I've tried commenting out the variable updates and the hanging continues in earnest, which suggests that the problem is in fact with the way I'm implementing the Parallel.For loop.
I have no problems tearing this down pretty much from scratch and rebuilding to get this working. My only really important design goal in that I have the same paradigm (one base class, multiple sub-classes for implementation of different slots).
Where am I going wrong?