InterviewSolution
| 1. |
Solve : C# Thread safe bitmaps in timer? |
|
Answer» Hi. I'm guessing BC programmer can help me with this engine = new GameEngine(); Here is the engine code: Quote class GameEngineUntil BC shows up, you may want to read t his over: http://stackoverflow.com/questions/11623039/how-to-make-objects-threadsafe-on-c Also: http://stackoverflow.com/questions/17975884/c-sharp-variable-thread-safety More: http://stackoverflow.com/questions/22229702/threadsafe-over-bitmap-in-c-sharp Quote Any public static (SHARED in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.I don't understand why it wouldn't be able to compile. Threading problems such as this usually result in an InvalidOperationException at run-time. Quote now it won't compile because I guess the bitmap and graphics objects are not thread safeIf it doesn't compile, it emits compile errors. Those would be useful to know. At any rate, you shouldn't be drawing in the timer procedure anyway. My game's 2-D "engine" loaded all bitmap assets at startup. the Bitmap constructor accepting a filename is unreliable, for what it's worth- to load Image data I used what is found here: Basically, instead of using the file, it read the entire file into a Memory Stream, and then used Image.FromStream(). It didn't use Bitmaps for assets, since they did not need to be changed. The actual game logic was in a separate thread. Which can be seen here (side note, If I was writing it now I would probably use an interface-based approach to "gamestates" rather than simply using an enum and a large switch statement). The separate Thread does absolutely no drawing- it simply performs the game logic. However, each frame it will also attempt to invoke a repaint: Code: [Select]PicGame.Invoke((MethodInvoker)(() => { PicGame.Invalidate(); PicGame.Update(); })); The Invoke is required because the GameProc() thread is not on the UI thread. only the UI thread can call the methods of Win Forms controls (otherwise, we get the aforementioned InvalidOperationException- "Cross-thread operation not valid" or something to that effect). In this case it simply invalidates the PictureBox being used to display the game and forces it to Update. In turn, this will cause the Picturebox's Paint event to be called- it get's called on the UI thread. Both the gameproc as well as the drawing routine however lock on certain things to prevent them both from accessing things simultaneously, which could cause problems. It paints to a backbuffer and then that backbuffer get's drawn to the Graphics object provided to the event (e.Graphics). I would never use a Timer for this sort of thing, since Timers are EXCEEDINGLY unreliable. I base this on having used Timers before, and finding them to be unreliable. This holds especially true if you are using the System.Windows.Forms.Timer. Quote I don't understand why it wouldn't be able to compile. Threading problems such as this usually result in an InvalidOperationException at run-time. You are correct. I was being inaccurate. What I meant to say was it has a run-time error with a message like you described. I see what your saying, but I don't understand why your game doesn't just run at full CPU speed if you're not using a timer to update your frames. Could you explain to me how I should do this instead of using a timer? If you know of any examples of rendering bitmaps using GDI at a specific speed, that would be useful. I'll take a look at the code for your game when I have some time.Quote from: Linux711 on May 12, 2014, 10:08:09 PM I see what your saying, but I don't understand why your game doesn't just run at full CPU speed if you're not using a timer to update your frames.It does run at full CPU speed. That is the entire point of not using Timers. The game logic runs as fast as it POSSIBLY can, if it goes faster than the desired framerate it will interpolate; if slower, than it will move objects faster. Whether the game receives CPU cycles is up to the Thread scheduler. Quote Could you explain to me how I should do this instead of using a timer? If you know of any examples of rendering bitmaps using GDI at a specific speed, that would be useful. I'll take a look at the code for your game when I have some time.Referring back to my game (I opened it for the first time in maybe a year and a half now...). Basically it tracks the FPS and if it's below 30 all movement and changes will be scaled appropriately; at 15fps for example an object will move faster each tick in order to keep up with what would be a normal rate. This prevents objects from actually moving slower, with the side effect of causing jerky motion (which also screws with other stuff such as hittesting, but that's another topic). A Timer is designed for- as it says on the tin- something you want to happen at a repeating rate. But more importantly no Timer implementation is particular stringent about that actual rate. It takes your 100ms as a guideline, not a rule. Additionally, using a Timer introduces idle time, which is what you want to avoid. It should run as fast as possible to make the experience as smooth as possible. |
|