예제 #1
0
        public void Stop()
        {
            const int thread_join_timeout = 30000;

            Threads.ForEach(t => t.Exit());
            Threads.Where(t => t.Running).ForEach(t =>
            {
                var thread = t.Thread;

                if (thread == null)
                {
                    // has already been cleaned up (or never started)
                    return;
                }

                if (!thread.Join(thread_join_timeout))
                {
                    Logger.Log($"Thread {t.Name} failed to exit in allocated time ({thread_join_timeout}ms).", LoggingTarget.Runtime, LogLevel.Important);
                }
            });

            // as the input thread isn't actually handled by a thread, the above join does not necessarily mean it has been completed to an exiting state.
            while (!mainThread.Exited)
            {
                mainThread.ProcessFrame();
            }

            ThreadSafety.ResetAllForCurrentThread();
        }
예제 #2
0
        public virtual void RunMainLoop()
        {
            // propagate any requested change in execution mode at a safe point in frame execution
            ensureCorrectExecutionMode();

            Debug.Assert(activeExecutionMode != null);

            switch (activeExecutionMode.Value)
            {
            case ExecutionMode.SingleThread:
            {
                lock (threads)
                {
                    foreach (var t in threads)
                    {
                        t.RunSingleFrame();
                    }
                }

                break;
            }

            case ExecutionMode.MultiThreaded:
                // still need to run the main/input thread on the window loop
                mainThread.RunSingleFrame();
                break;
            }

            ThreadSafety.ResetAllForCurrentThread();
        }
예제 #3
0
        public void Stop()
        {
            const int thread_join_timeout = 30000;

            // exit in reverse order so AudioThread is exited last (UpdateThread depends on AudioThread)
            Threads.Reverse().ForEach(t =>
            {
                // save the native thread to a local variable as Thread gets set to null when exiting.
                // WaitForState(Exited) appears to be unsafe in multithreaded.
                var thread = t.Thread;

                t.Exit();

                if (thread != null)
                {
                    if (!thread.Join(thread_join_timeout))
                    {
                        throw new TimeoutException($"Thread {t.Name} failed to exit in allocated time ({thread_join_timeout}ms).");
                    }
                }
                else
                {
                    t.WaitForState(GameThreadState.Exited);
                }

                Debug.Assert(t.Exited);
            });

            ThreadSafety.ResetAllForCurrentThread();
        }
예제 #4
0
        private void ensureCorrectExecutionMode()
        {
            if (ExecutionMode == activeExecutionMode)
            {
                return;
            }

            if (activeExecutionMode == null)
            {
                // in the case we have not yet got an execution mode, set this early to allow usage in GameThread.Initialize overrides.
                activeExecutionMode = ThreadSafety.ExecutionMode = ExecutionMode;
            }

            // shut down threads in reverse to ensure audio stops last (other threads may be waiting on a queued event otherwise)
            foreach (var t in Threads.Reverse())
            {
                t.Pause();
            }

            switch (ExecutionMode)
            {
            case ExecutionMode.MultiThreaded:
            {
                // switch to multi-threaded
                foreach (var t in Threads)
                {
                    t.Start();
                    t.Clock.Throttling = true;
                }

                break;
            }

            case ExecutionMode.SingleThread:
            {
                // switch to single-threaded.
                foreach (var t in Threads)
                {
                    // only throttle for the main thread
                    t.Initialize(withThrottling: t == mainThread);
                }

                // this is usually done in the execution loop, but required here for the initial game startup,
                // which would otherwise leave values in an incorrect state.
                ThreadSafety.ResetAllForCurrentThread();
                break;
            }
            }

            activeExecutionMode = ThreadSafety.ExecutionMode = ExecutionMode;

            updateMainThreadRates();
        }
예제 #5
0
        private void ensureCorrectExecutionMode()
        {
            // locking is required as this method may be called from two different threads.
            lock (startStopLock)
            {
                // pull into a local variable as the property is not locked during writes.
                var executionMode = ExecutionMode;

                if (executionMode == activeExecutionMode)
                {
                    return;
                }

                activeExecutionMode = ThreadSafety.ExecutionMode = executionMode;
                Logger.Log($"Execution mode changed to {activeExecutionMode}");
            }

            pauseAllThreads();

            switch (activeExecutionMode)
            {
            case ExecutionMode.MultiThreaded:
            {
                // switch to multi-threaded
                foreach (var t in Threads)
                {
                    t.Start();
                }

                break;
            }

            case ExecutionMode.SingleThread:
            {
                // switch to single-threaded.
                foreach (var t in Threads)
                {
                    // only throttle for the main thread
                    t.Initialize(withThrottling: t == mainThread);
                }

                // this is usually done in the execution loop, but required here for the initial game startup,
                // which would otherwise leave values in an incorrect state.
                ThreadSafety.ResetAllForCurrentThread();
                break;
            }
            }

            updateMainThreadRates();
        }
예제 #6
0
        private void ensureCorrectExecutionMode()
        {
            if (ExecutionMode == activeExecutionMode)
            {
                return;
            }

            // if null, we have not yet got an execution mode, so set this early to allow usage in GameThread.Initialize overrides.
            activeExecutionMode ??= ThreadSafety.ExecutionMode = ExecutionMode;
            Logger.Log($"Execution mode changed to {activeExecutionMode}");

            pauseAllThreads();

            switch (ExecutionMode)
            {
            case ExecutionMode.MultiThreaded:
            {
                // switch to multi-threaded
                foreach (var t in Threads)
                {
                    t.Start();
                    t.Clock.Throttling = true;
                }

                break;
            }

            case ExecutionMode.SingleThread:
            {
                // switch to single-threaded.
                foreach (var t in Threads)
                {
                    // only throttle for the main thread
                    t.Initialize(withThrottling: t == mainThread);
                }

                // this is usually done in the execution loop, but required here for the initial game startup,
                // which would otherwise leave values in an incorrect state.
                ThreadSafety.ResetAllForCurrentThread();
                break;
            }
            }

            activeExecutionMode = ThreadSafety.ExecutionMode = ExecutionMode;

            updateMainThreadRates();
        }