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
"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.