Domanda

I have already seen questions on the same topic but couldn't figure out how to solve this problem. In my game, I am using two threads one Logic thread and the UI thread. This is the problem I'm having

System.InvalidOperationException: Object is currently in use elsewhere.
   at System.Drawing.Graphics.FromImage(Image image)
   at GECS.Core.Game.UpdateLoop() in c:\Us....ore\Game.cs:line 82
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

I was rendering only on the UI thread. Here's my rendering loop. I placed it right in the constructor.

while (true) {
    if (!Created) {
        break;
    }
    if (Win32.PeekMessage(out msg, IntPtr.Zero, 0, 0, (uint)Win32.PM.REMOVE)) {
        if (msg.message == (uint)Win32.WindowsMessage.WM_QUIT) {
            break;
        } else {
            Win32.TranslateMessage(ref msg);
            Win32.DispatchMessage(ref msg);
        }
    } else {
        Text = Global.TITLE;
        now = GetCurrentTime();
        Graphics front = Graphics.FromHwnd(Handle);
        front.DrawImage(backBuffer, 0, 0);
        front.Dispose();
    }
}

And my logic loop

while (Created) {
    now = GetCurrentTime();
    while (now > game_time) {
        elapsedTime = 1000/Global.ACTUAL_STEPS_FOR_SECOND;
        Update(elapsedTime);
        Map.UpdateObjects(elapsedTime);
        game_time += step_size;
    }
    Graphics g = Graphics.FromImage(backBuffer);   // This line is error
    g.Clear(Color.WhiteSmoke);
    Render(g);
    g.Dispose();
}

How can I solve this problem? Already tried pasting the logic loop on top of render loop which made my game so slow.

Thanks

È stato utile?

Soluzione

"Two threads" is of course the problem. They cannot allow both threads to access the backBuffer at the same time. You must use a lock to prevent this from happening. Roughly:

private object bufferLock = new object();
...
    using (var front = Graphics.FromHwnd(Handle)) {
        lock (bufferLock) {
            front.DrawImage(backBuffer, 0, 0);
        }
    }

and

    lock (bufferLock) {
        using (var g = Graphics.FromImage(backBuffer) {  // No more error
            g.Clear(Color.WhiteSmoke);
            Render(g);
        }
    }

The rest doesn't look that healthy either, you are not making sure you properly ping-pong between the two threads and it is very unclear what thread owns the window.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top