private void OnFinished(bool success) { _eventExecutor.EnqueueAction(HandleIt); void HandleIt() { if (!success) { _cancelled.TrySet(); } _arbiterThread.Dispose(); WaitForWriterThreadThenDispose(TimeSpan.FromSeconds(5)); foreach (var thread in _readerThreads) { thread.Dispose(); } string finalString = _stringVault.CopyCurrentValue(TimeSpan.FromSeconds(10)); int xCount = finalString.Count(c => c == XChar); int oCount = finalString.Count(c => c == OChar); int? winningThreadIndex = _winningArgs?.ThreadIdx; ClortonGameEndedEventArgs args = new ClortonGameEndedEventArgs(_startTime, _endTime ?? TimeStampSource.Now, _cancelled.IsSet, finalString, xCount, oCount, winningThreadIndex); OnGameEnded(args); } void WaitForWriterThreadThenDispose(TimeSpan timeout) { bool xStarted = _xThread.ThreadActive; bool oStarted = _oThread.ThreadActive; DateTime quitAfter = CgTimeStampSource.Now + timeout; while ((!xStarted || !oStarted) && CgTimeStampSource.Now <= quitAfter) { Thread.Sleep(TimeSpan.FromMilliseconds(1)); xStarted = _xThread.ThreadActive; oStarted = _oThread.ThreadActive; } if (xStarted) { _xThread.Dispose(); } else { try { _xThread.Dispose(); } catch (Exception ex) { Console.Error.WriteLine( $"X thread was not started when it was disposed and exception thrown: [{ex}]."); } } if (oStarted) { _oThread.Dispose(); } else { try { _oThread.Dispose(); } catch (Exception ex) { Console.Error.WriteLine( $"O thread was not started when it was disposed and exception thrown: [{ex}]."); } } } }
private protected virtual void OnGameEnded([NotNull] ClortonGameEndedEventArgs e) => GameEnded?.Invoke(this, e);