Control game ticks/frames of updates and rendering separately I am working on a bigger project and want to separate game updates from rendering and not end up with a super complicated game loop. So I came up with the idea of isolating the problem and writing a controller for this. My game loop looks like:

public class Game {
    public bool Running;

    public void Loop()
    {
        var update = new FrameController(10, 30, true, Update);
        var render = new FrameController(1, 1000, false, Render);

        while (Running)
        {
            update.TryFrame();
            render.TryFrame();
        }
    }

    public void Update(double delta_time)
    {
        [...]
    }

    public void Render(double delta_time)
    {
        [...]
    }
}


And my tick/frame controller looks like:

public class FrameController
{
    protected double DeltaTime;
    protected readonly double MaxDeltaTime;
    protected readonly double MinDeltaTime;
    protected readonly bool SlowCatchUp;
    protected readonly Action&lt;double&gt; Action;
    protected readonly Stopwatch Watch;

    public FrameController(int min_fps, int max_fps, bool slow_catch_up, Action&lt;double&gt; action)
        : this(slow_catch_up, action)
    {
        MaxDeltaTime = 1.0 / min_fps;
        MinDeltaTime = 1.0 / max_fps;
    }

    public FrameController(double min_delta_time, double max_delta_time, bool slow_catch_up, Action&lt;double&gt; action)
        : this(slow_catch_up, action)
    {
        MaxDeltaTime = min_delta_time;
        MinDeltaTime = max_delta_time;
    }

    protected FrameController(bool slow_catch_up, Action&lt;double&gt; action)
    {
        SlowCatchUp = slow_catch_up;
        Action = action;
        Watch = new Stopwatch();
        Watch.Start();
    }

    public void TryFrame()
    {
        var delta_time = Watch.Elapsed.TotalSeconds;
        Watch.Restart();
        DeltaTime += delta_time;

        if (DeltaTime &lt;= MinDeltaTime)
            // Skip
            return;
        else if (DeltaTime &gt;= MaxDeltaTime)
            DoFrame(SlowCatchUp ? MaxDeltaTime : DeltaTime);
        else
            DoFrame(DeltaTime);
    }

    protected void DoFrame(double delta_time)
    {
        Action(delta_time);
        DeltaTime -= delta_time;
    }
}


The updates will fire 10 to 30 times per second and if the game hangs they will slowly catch up to the current state. Apart from this the rendering will fire 1 to 1000 times per second (just for testing) and if the game hangs they will catch up immediately. If the game is running to fast frame will be skipped.

Any input and critique is welcome!
I think sourcing the game-loop out is basically a good idea to improve separation of concerns. But I would go farther: I would implement a strategy pattern which makes the behavior of the game loop exchangeable. Futhermore I would source out the loop itself, too.

public interface IGameLoop{
    void Start();
    void Stop();
}
public interface IUpdateBahvior
{
    bool TryUpdate();
}
public interface IRenderBehavior
{
    bool TryRender();
}


Example implementation: 

class SynchronGameLoop : IGameLoop
{
    private bool _isRunning;
    private readonly IUpdateBehavior _updateBehavior;
    private readonly IRenderBehavior _renderBehavior;

    public SynchronGameLoop(IUpdateBehavior updateBehavior, IRenderBehavior renderBehavior){
        _updateBehavior = updateBehavior;
        _renderBehavior = IRenderBehavior ;
    }

    public void Start(){
        if(_isRunning) return;
        while(_isRunning){
            _updateBehavior.TryUpdate();
            _renderBehavior.TryRender();
        }
    }
    public void Stop()
    {
        _running = false;
    }
}

class AsyncGameLoop : IGameLoop ...

class StatisticProvidingGameLoop: IGameLopp ...


This system offers you the possibility to exchange the game loop behavior at run-time. So If you decide to implement a game loop that offers statistic information(update count, update time, render count) for debugging purpose, you free to exchange this, without altering your code. 

The separation into two *behavior interface provide the possibility to implement completely independent strategies, for this two functionality. But if you wish to, one class can implement both interfaces and can make the functionality dependent on each other. So while implementing your engine, you don't define what kind of game loop and update/render behavior is finally used. For example in XNA, you can switch between fixed time steps and variable one. All this is easily possible with the strategy pattern.