Draw() not updating (or there's a lot of computation without drawing)

I was wondering that. I was beginning to suspect that Draw isn’t actually executed until Draw() completes. Thanks for clearing that up.

Did you create threads via TASK or via ASYNC?

I used Async, so it was always running and send messages through static variables as flags, I know maybe this is not the correct way but it worked fine for my game.

I tried TASK and it didn’t solve the problem. I’ve set up LOTS of boolean message flags (that seems to be the way that MonoGame wants you to communicate with Draw() to make messages appear). A friend in Belfast will help me with the Aync via videoconference.

Thanks!

you should not do the if (doingTheLongProcess) where its been suggested, thats on the UI thread still, in update… You would call the long AI process code from inside the task run brackets…

also your doingtheLongProess should be atomic and thread safe … you might get away wiht it… but its not a proper lock.

here is some minor tweaks that might make it work… a bit but you should look at producer consumer patterner and WaitHandles… unless this works and its good enough yhou only have one thread to manage so maybe…

atomic bool startTheLongProcess = false; //this isnt a normal lock it might be ok tho.
atomic bool doingTheLongProcess = false;

atomic static int progess =0;

void Update()
{
if (startTheLongProcess)
{
startTheLongProcess = false;
doingTheLongProcess = true;

	Task.Run(() =>
	{
		// this code will run in a separate thread, and so your Update()/Draw() cycles will continue while this runs separately

		// do your long process stuff here
		// WARNING!! Anything that happens in here must be thread-safe! thread-unsafe code is very difficult to debug (i.e. when this thread and the main thread both try to write to the same var or something - won't always happen, but when it does your game will just crash or malfunction and you won't have any idea why)
                    DoAICode here that might take long..   keep  updatng ur progress.. maybe progress++  BTW this isnt really how mutlthreading code is supposed to be synced but it might work..

		doingTheLongProcess = false;
	});
}

//ISSUE this is still on the UI thread it will block that draw…
if (doingTheLongProcess)
{
//DONT here

	// run updates that should happen during the running of the long process, like updating animations/messaging to the user about the long process
}
else
{
	// normal update stuff here   .. if need to be on ui thread..

	// within this normal updates, you hit the condition that needs your long process

	// trigger your condition for the long process....
	startTheLongProcess = true; // the reason you'd do this instead of just starting the long process here is you don't want to risk making thread-unsafe code by starting a process here and potentially having something else within these normal update scripts that could be writing to the same vars and whatever else. Using this method, if you ensure that you only ever have changes to common vars within this else and within the long process's separate task, you won't need to worry about using locks and what not since they could never be running at the same time.
}

}

void Draw()
{
if (doingTheLongProcess)
{
// display whatever message/animation/etc to the user about the long process running
}else
{

draw the next frame…

}

}

cant guarantee this will work but the other wayh will still block the ui thread… i dont do anything on UPdate… all my physics is spun on a worker thread, then copy all drawable stuff to a frame, then works on the next frame…so i dont need a lock… then on draw i draw the last finished frame… thats producer consumer… i run like 4000 fps on physics and draw at 60 hz… its sort of the oppostite , def dont put code that takes more than 16 ms on the update call…

sorry just saw this correction i repeated it … still i think its needs more syncing … like producer consumer pattern…

Don’t bother with async stuff. It’ll only introduce more errors which are way harder to catch. Use coroutines instead. Coroutines are like async tasks, but they actually run on the same thread and are interrupted after a certain amount of frametime only to be resumed on the next frame. No syncing required.

You can yoink my implementation:

Example usage:

Martenfur,

Just a question about your implementation of coroutines, if you have a big loop where you have to update all your units and if that one takes a lot of time over the allocated time, what will happen?
will it yield in the middle and continue with the exact unit the next frame? or will it just yield out and a special logic should be allocated so the process can continue with the next unit?

Also, I agree that Async is more difficult to debug, but since it is processed in a different thread it really free ups the game to do much more at the same time, more than a coroutine can do, it depends on how many things you want to do per frame, but I think having parallel threads is more effective, specially if you have 4 or more cores, the game can use all of them and get really fast and do many more complex things per frame.

It yields where you tell it to yield. Then it checks if you still have the time budget left. If you do, it returns control right back to the function. If not, it suspends it and resumes on the next frame. But for that, you yourself have to put yield returns, if you don’t, you will essentially get a regular function.

This is only how Jobs behave, however. There are regular coroutines and they have a different, more traditional behavior. Jobs are only for big background tasks that we need to extend.

And yes, sure, going true multithreaded is the theoretically ideal option, but you REALLY need to know what you’re doing.

First, thanks for all the replies. I’m about half-way there; which is to say there are, apparently, only 2 methods that are not returning fast enough for Draw()'s liking. As you can see from this screen shot, I’m getting some of my messages displayed (circled in red):


I’m doing this by setting a series of boolean message flags. There are a series of 4 methods in Update() and as each one is completed it turns off that boolean flag and turns on the next one. HOWEVER, only 2 of the four messages are being displayed so I suspect that those methods are going away too long for Draw().

I have a good friend who is quite familiar with Async. I would like to see if he can get it working though he can’t look it at it for a while.

Not sure why you use multiple booleans when a simple integer (or enum) would be easier and maybe better readable. “async” in its basic form is just a “State Machine” which is what you are using anyway I guess. No matter, it will work that way, so you just split your “long function” into subsections (states) and exit after each section, increment the state and call a draw, so the draw does whats needed for that state change. async is jsut another way of syntax for that, so youc an do such behaviour without async as well. It won’t run parallel but serial. Normally you’d have your function with a big switch for each state and exit after each state, so the draw can be called.

Not ideal, but may work well enough for what you wanna achieve and you don’t need to learn about async or even threading.

void Update(...)
{
    ProcessState(current_state);
}

void Draw(...)
{
    DrawState(current_state);
}

void ProcessState(int state)
{
    switch(state)
    {
        case STATE_CALCFOG: ....
            state = <next_state>
            return;
        // etc etc
    }
 }

you get the idea. Be aware tho, Update may get called multiple times before Draw is called because Fixed Timestep. Turn that of or handle everything in Draw. It’s jsut the “easiest” way to do it, not the best (far away from the best) - just wanna introduce you to what a state machine could look like (and yes, you can achieve the same thing with “async” keyword without the switch and possible with much more readable code)

If your friend is fine with threads, that would be the better approach to handle your case, but there is lots of things you can do wrong without knowledge about it.

Thanks!