Interacting with a loop from outside its scope?

Hey guys!

Following my last post on me trying to build a console GUI with SDL_2. I'm running into a bit of an issue, by running I should rather say faceplanting a wall :).

I've built the console, and it works fine. Only, before starting to code I hadn't thought about one thing. I can cout things to the console, I can cin and all the test I've tried to do worked fine.

The thing Is that my console is running on a loop which roughly goes like this:
while (console is running)
-> run at 30 fps
-> handle console events (like user input, cin, cout, exiting...)
-> render console
loop

The whole console is wrapped in a class and therefore my main function looks like so:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "SDL_console.h"

using namespace std;


int main(int argc, char* args[])
{
	SDL_Console console;

	console.runWithCappedFrames();    //this is the loop function

	console.close();    //this closes console and destroys all allocated memory

	return 0;
}


The thing is, I'd like to be able to call the console functions from an object like in this example where console is a SDL_Console. However I'd like to be able to pass arguments to that object from outside said object's loop. As you understand, there is no passing console.runWithCappedFrames(); in the main function until you close the console..

I'd like to use that console now, with a regular program, and I guess what it should lool like is this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "SDL_Console.h"
#include <iostream>

using namespace std;

int main()
{
    SDL_Console console;

    int number;

    console.console_cout("Please enter a number between 1 and 10: ");
    number = console.console_cin();

    console.console_cout("\nThe number you chose is: ");
    console.console_cout(number);

    return(0);
}


Hopefully you see what I mean and the issue I'm having. I'm aware it may be a HUGE design flaw on my part, if so please point it out and suggest me a way of doing it, for I'm clueless.

Thanks in advance for all insight and help.

Regards,

Hugo.
I lost what you were doing in the other thread and am not 100% sure here, but I will just ask:
can you kick off the console.runWithCappedFrames(); as a thread, and with some care about mutex etc problems, get it working so the main thread can send it parameters or whatever?

The console should probably be an independent program. You can possibly interact with it through redirecting standard input/output or through IPC.

It seems strange to me that you would run a console at 30fps (or any fps). Are you polling for events (SDL_PollEvent)? It makes more sense to wait for events (SDL_WaitEvent).
if I followed it all, its a graphics program that behaves like a console, so it may need to be drawn at some rate to keep it clean when stuff is moved over its graphics window (like the mouse, etc). Otherwise you may get that effect (at least in windows, its sadly common) where a window just displays whatever was dragged over it last until something triggers a redraw. There are ways to draw only when needed...
Last edited on
A terminal/console is not usually displayed with a frame rate (it would be very wasteful). It should receive a redraw event when it needs to be redrawn. Then again, a console is not usually created with SDL. Something like Qt would be more common.
Last edited on
@jonnin

>can you kick off the console.runWithCappedFrames(); as a thread, and with some care about mutex etc problems, get it working so the main thread can send it parameters or whatever?

I was afraid someone would mentions threads, I have no knowledge about them and can't seem to find any good documentation on how to learn to use them. So I'm unable to answer your question.


>if I followed it all, its a graphics program that behaves like a console

Exactly.


>so it may need to be drawn at some rate to keep it clean when stuff is moved over its graphics window (like the mouse, etc)

Yes that's why I chose to use a fps cap, now set to 30, but could as well be 10, the memory usage isn't much different and really low anyway.


@dutch

>Are you polling for events (SDL_PollEvent)? It makes more sense to wait for events (SDL_WaitEvent).

Yes I am polling events, though I don't know how waitevent works, I suppose it wouldn't allow me to animate stuff onto the window, such as a blinking cursor for instance. Also if you wait for events you still end up using a loop (right?) so what's the real benefit from doing so?


> Then again, a console is not usually created with SDL. Something like Qt would be more common.

Yes you're probably right, however I wanted to created something that looked nice, since it's supposed to always be on my desktop. I already made the program I want to run work with a simple windows console, but I want something nice to look at, plus I guess it's some good mileage to try and program something like that.
You sound a little snarky. I was just trying to help. :-(
You sound a little snarky. I was just trying to help. :-(

Man.. I'm really sorry, it's not at all how I wished to sound, after re-reading my answers, I see what you mean and It's even bugging me.

I don't know if it's either me being tired or english not being my native language, but I do apologise.

I also didn't thank you for you and jonnin's feedback, which I should have. It is much appreciated, Thank you a lot, and again, my apologies..


EDIT: I guess I was just trying to ask you, if I use waitevents instead of polling them, would that mean I no longer need a loop to run the console? I though of changing my while loop to an if statement (if console is running) but wouldn't that mean you could miss events if they happen outside the scope of the function containing the loop/statement?
Last edited on
I hate to say it but if you decide to do threads, you have to put this project down for a day or two, and play with thread examples. There are different libraries so syntax varies a little for threads, and the language has some of it built in now too, but I am very out of practice with them.

I hesitate to offer any examples because last time I did it was with afx threads (specific to visual studio) on VS 2008 or 2005. I would likely lead you far astray of the current way to do them. Ive used them for some microscopic code since via pthreads but I am still rusty on anything complex (I avoid mutex issues and typically am just splitting stuff into quarters for speed, 4 copies of identical thread on a 4-core cpu).

the basic idea is you would have the drawing in the background threaded, just doing its thing drawing the current graphics. The rest of the interactions can be moved away and the thread would just draw the current version ...
Last edited on
@jonnin

Yes.. I think it's what I'm going to end up doing. I don't mind putting my project aside for a few days, since I have on the one hand the console that's done and ready and on the other the program that I want to "link" to the console, which is also done. I guess it's just a matter of finding a way around this issue I'm having for now..

I'll just have to find some good documentation/tutorial but I'm going to get to it :)

>the basic idea is you would have the drawing in the background threaded, just doing its thing drawing the current graphics. The rest of the interactions can be moved away and the thread would just draw the current version ...

Am I right in assuming you can pass things from one thread to another?

Thanks for your feedback!
you need to use shared memory or various similar concepts to share across threads.

some ideas:

if you have some kind of class console, and it has some method drawme() or whatever (I am not looking back and forth at your code to here), you can make static members to pass the data (so if it changes in the copy in thread A or the main thread or wherever else, it also changes in the local copy of thread B)

if you need more than 1 console, the above does not work. Then you may need to pass console variables to the thread function, and keep a pointer to the same instance in main, so that if you change the class member variables (not static) in main, they change in the thread, for each copy of the class. Same idea, you just lose the staic shortcut (singleton, really) pattern and have to do slightly more work to keep a handle on all your class instances so you can update.

In both of those cases, you need a mutex, so that changing the variable in one is done in sync with using it in the other.

you can also use shared memory for this, but that may be way overkill -- it depends on what you need to do, though. If you need it, you need it.

you can also use a pseudo-global, eg a static class variable (its own class, not part of the console this time). For example make a little struct with a static array of 4 Booleans as its only member, set them false, kick off 4 threads, each sets one of the locations true when done, main thread waits on all 4 to be true... a simple solution to a simple problem.
if you wait for events you still end up using a loop (right?) so what's the real benefit from doing so?
There's no loop. Typically the program waits for input or a signal, so it's pretty friendly to your CPU and your cooling fan.
>if you have some kind of class console, and it has some method drawme() or whatever (I am not looking back and forth at your code to here), you can make static members to pass the data (so if it changes in the copy in thread A or the main thread or wherever else, it also changes in the local copy of thread B)

What do you mean by it changes the local copy of thread A or B?
Yes I have a class console which has a render function. It runs within the main class loop which, if you're interested, looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
bool SDL_Console::runWithCappedFrames()
{
	if (isRunning())
	{
		if (firstIterationAfterInit())
		{
			fpsTimer.start();

			cout << "\n_____CONSOLE____________________"
				<< "\n\t\t\t\t|"
				<< "\nGame is capped at " << GlobalConsoleSettings::SCREEN_FPS << " FPS!\t|"
				<< "\n________________________________|\n\n\n"
				<< "_____CONSOLE_RUNNING_____\n\n";
		}
		else
		{
			capTimer.start();
			float avgFPS = countedFrames / (fpsTimer.getTicks() / 1000.f);
			if (avgFPS > 2000000) avgFPS = 0;

			if (countedFrames > GlobalConsoleSettings::SCREEN_FPS)
				countedFrames -= GlobalConsoleSettings::SCREEN_FPS;

			handleConsoleEvents();
			render();

			countedFrames++;

			int frameTicks = capTimer.getTicks();
			if (frameTicks < GlobalConsoleSettings::SCREEN_TICK_PER_FRAME)
			{
				//Wait remaining time
				SDL_Delay(GlobalConsoleSettings::SCREEN_TICK_PER_FRAME - frameTicks);
			}
		}
	}
	

	return isRunning();
}

EDIT: you may notice this is not a loop anymore, the reason why is I looped it from main to see if I could change anything, but I couldn't figure out anything so far..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "SDL_console.h"

using namespace std;


int main(int argc, char* args[])
{
	SDL_Console console;

	while (console.runWithCappedFrames())
	{

	}

	console.pause();
	console.close();

	return 0;
}


I'll have to look into mutex, since I don't know what that is at all, as well as shared memory. I'm still looking for ressource on threads, unsuccessfully so far.

Thanks for suggesting all that, that gives me much material to look for and study!
Last edited on
What do you mean by it changes the local copy of thread A or B?
Yes I have a class console which has a render function. It runs within the main class loop which, if you're interested, looks like this:
-------------------------------------------------
Just how 'static' works in a class.
If you have class console, and it has inside it static int x, for example,
then if have a local console in thread a, and a local console in thread b, and either one of them changes X, its the SAME X. So if A changes X, B can read X and get A's value, etc. Its ONE way to share memory, but it does not scale well to having a bunch of the class around. This has nothing to do with threading so much as just using the way static works as a tool along-side the threading. If you had 3 threads it makes less sense unless one changes and 2 read, but at some point, this 'trick' isn't sufficient. If you only have 1 console per program instance, it may be all you needed.


--------------------

I'll have to look into mutex, since I don't know what that is at all
a mutex stands for mutually exclusive (which means two things that cannot exist at the same time in the same state. That is, if one is true the other is false. They can't both be true at once.). Its a tool build into threading libraries, so you will hit it when you study. Better to read something well written on them.

if you can't find a generic source on threading, try
https://www.tutorialspoint.com/cplusplus/cpp_multithreading.htm

or the c++11 tools:
https://thispointer.com/c-11-multithreading-part-1-three-different-ways-to-create-threads/


Last edited on
Topic archived. No new replies allowed.