1

I recently noticed that my game cycle wasn't executing itself. If I reboot the server it can fix it, this is totally random and can take anywhere from 1 to 4 restarts to fix it. It seems to happen more when I git pull before running the server, I have a feeling its connected to system time

I'm targeting DotNet core 3.1 on Ubuntu 18.06, and here is how I run my application.

dotnet build
dotnet run --project=Server

I've tested it on windows also, the same issue. I've also tested it on another Ubuntu machine and the same happens.

Here is the ccode

public class Game
{
    private bool _cycleEnded;
    private bool _cycleActive;
    private Task _gameCycle;
    private int _cycleSleepTime = 25;

    public Game()
    {
        _gameCycle = new Task(GameCycle);
        _gameCycle.Start();

        _cycleActive = true;
    }

    private void GameCycle()
    {
        // Determine if the cycling is even happening?
        Console.WriteLine("Attempting to cycle the game");

        while (_cycleActive)
        {
            _cycleEnded = false;

            Root.GetGame().GetRoomManager().OnCycle();
            Root.GetGame().GetClientManager().OnCycle();

            _cycleEnded = true;
            Thread.Sleep(_cycleSleepTime);
        }
    }
}
  • 2
    Doesn't `_cycleActive` have to be true before you start the `GameCycle()` routine? This isn't a whole lot of code to give us. – LarsTech Feb 11 '20 at 20:47
  • TBH, you don't need the var anyways, it's private, you could remove it. **Or** set it `true` by default and get rid of the assignment... – Trevor Feb 11 '20 at 21:17

1 Answers1

4

It isn't randomly not calling the function. Sometimes the function is called before _cycleActive is true; sometimes _cycleActive is set to true before the function is called. It's random and unpredictable. That's why your attempts to resolve this sometimes "fixes" it: its not actually fixing the issue, the issue is simply random.

Here's why: you are setting _cycleActive to true after starting the task. That task starts running right away, and it's a race to see who wins: setting the boolean, or testing the boolean.

When the code hits while (_cycleActive), _cycleActive may or may not have been set to true.

You have a race condition:

A race condition occurs when two or more threads can access shared data and they try to change it at the same time. Because the thread scheduling algorithm can swap between threads at any time, you don't know the order in which the threads will attempt to access the shared data. Therefore, the result of the change in data is dependent on the thread scheduling algorithm, i.e. both threads are "racing" to access/change the data.

Set it to true before starting your task. This will ensure it is ready for use by the task, thus eliminating the race condition.

Also see MSDN: lock statement for a more general approach to preventing race conditions by using thread synchronization.

  • 2
    @Çöđěxěŕ The observed behavior depends on whether the value is set first, or whether the value is tested first. That is a race condition. –  Feb 11 '20 at 20:51
  • 1
    @Çöđěxěŕ This is a race condition. It is so clearly a race condition, I have no idea what else you think it *could* be. – Christopher Feb 11 '20 at 20:53
  • 1
    Yes, setting the value before starting the task eliminates the race condition. You have multiple threads trying to read/write that boolean. This is indisputably a race condition. –  Feb 11 '20 at 20:53