You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenTK中GameWindow打开后整数停更、定时器失效问题求助

Hey there! Let's break down and solve those OpenTK issues you're facing one by one—they're all tied to how GameWindow handles its main thread and message loop, so once we clarify that, things will click into place.

1. Integer Stops Changing When GameWindow Opens

The root cause here is that GameWindow.Run() blocks your main thread entirely once it starts the game loop. If your integer-updating code runs before Run(), it’ll never reach the window launch; if it’s after Run(), it won’t execute until the window closes.

The fix is to move your integer updates into the UpdateFrame event, which fires every tick of the game loop (on the main thread):

private int _counter = 0;

public MyCustomGameWindow()
{
    // Hook into the update frame event
    UpdateFrame += OnUpdateFrame;
}

private void OnUpdateFrame(object sender, FrameEventArgs e)
{
    _counter++; // This will update continuously while the window is running
}
2. Keeping the Integer Updating in the Background

If you want the integer to update on a separate background thread (instead of the game loop), you need to handle thread safety—since the game loop runs on the main thread, accessing the integer from both threads can cause race conditions.

Option 1: Use Interlocked for Atomic Operations

This ensures safe read/write operations across threads:

private int _counter = 0;
private Thread _backgroundThread;

public MyCustomGameWindow()
{
    _backgroundThread = new Thread(BackgroundUpdateLoop);
    _backgroundThread.IsBackground = true; // Ends when the app exits
    _backgroundThread.Start();
}

private void BackgroundUpdateLoop()
{
    while (true)
    {
        Interlocked.Increment(ref _counter); // Atomic increment
        Thread.Sleep(100); // Adjust update frequency as needed
    }
}

// Safely read the value in the game loop
private void OnRenderFrame(object sender, FrameEventArgs e)
{
    int currentCount = Interlocked.CompareExchange(ref _counter, 0, 0); // Safe read
    // Render currentCount to the window here...
}

Option 2: Modern Task-Based Approach

Using Task and CancellationToken for cleaner background task management:

private int _counter = 0;
private CancellationTokenSource _cts;

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    _cts = new CancellationTokenSource();
    Task.Run(BackgroundUpdateAsync, _cts.Token);
}

private async Task BackgroundUpdateAsync()
{
    while (!_cts.Token.IsCancellationRequested)
    {
        Interlocked.Increment(ref _counter);
        await Task.Delay(100, _cts.Token); // Non-blocking delay
    }
}

protected override void OnUnload(EventArgs e)
{
    base.OnUnload(e);
    _cts.Cancel(); // Clean up the background task
}

⚠️ Important: Never call OpenTK window/rendering methods from a background thread—all UI-related operations must happen on the main thread (in UpdateFrame or RenderFrame).

3. Timer Not Executing After GameWindow Shows Up

Most standard .NET timers struggle with GameWindow’s message loop:

  • System.Windows.Forms.Timer relies on Windows Forms’ message loop, which GameWindow doesn’t use.
  • System.Timers.Timer runs callbacks on background threads, and calling window methods (like Exit()) from there can fail due to thread mismatches.

Best Fix: Use GameWindow’s Built-In Frame Timing

The most reliable way is to track time directly in the game loop:

private double _startTime;

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    _startTime = DateTime.Now.TotalSeconds;
}

private void OnUpdateFrame(object sender, FrameEventArgs e)
{
    double elapsedTime = DateTime.Now.TotalSeconds - _startTime;
    if (elapsedTime >= 2)
    {
        Exit(); // Close the window after 2 seconds
    }
}

Alternative: Use System.Threading.Timer with Main Thread Invoke

If you prefer using a timer, use System.Threading.Timer and invoke the window close on the main thread:

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    // Trigger once after 2000ms (2 seconds)
    var closeTimer = new System.Threading.Timer(_ =>
    {
        // Switch to the main thread to safely close the window
        Invoke(() => Exit());
    }, null, 2000, Timeout.Infinite);
}

内容的提问来源于stack exchange,提问作者Arkadiusz Brzoza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:43:51