1
\$\begingroup\$

The game I am creating displays a menu before starting, the user may select to start the game, or do some stuff. When the user selects an option, I need to call another function which actually does the selected option (start the game, configuration, etc...), the problem is that since I called that function from the menu function all the variables from the menu stay in memory. So I want to finish the menu function and remove all of its contents from memory and then start the function corresponding to the option selected, if the user goes back to the menu then load everything again and unload it when its finished. The problem is I there is no way (that I'm aware of) to tell the menu function which function to call after it finishes.

I though about starting the function corresponding to the option selected in another thread while the menu function finishes (what could possibly go wrong...) like this:

int menu()
{
    Load_menu_stuff_to_memory();

    int quit = 1;
    while(quit)
    {
        if(option_a_selected)
        {
            //the new function will be started in a new thread while the menu one finishes
            quit = 0;
            start_option_a_in_new_thread();
        }else if(option_b_selected)
        {
            //the new function will be started in a new thread while the menu one finishes
            quit = 0;
            start_option_b_in_new_thread();
        }
    }

    Deallocate_menu_stuff();
}

But I'm not sure if the new thread will end when the menu function does or be left like in the limbo or something.

Also I'm not sure if when the menu function ends the program will reach end of main (not to be confused with menu)

So: will my method work?

if not:

how can I call a random function but only after the caller function has finished?

\$\endgroup\$
  • \$\begingroup\$ What's wrong with having the menu still be in memory when you call your new function? \$\endgroup\$ – congusbongus Oct 27 '14 at 3:11
  • \$\begingroup\$ First because it's sort of inefficient and because I plan to port it to mobile at some point. I'm using SDL and don't want to rewrite it to use activities (in Android) because I don't know Java. Besides if I want to call an option from another option I would either have to leave both in memory or go back and have the user select it manually I from the main menu which would be annoying.. \$\endgroup\$ – user3195897 Oct 27 '14 at 3:16
  • \$\begingroup\$ Are you using a state machine for your overall game state? It's common to use one for exactly this, and then you make the menu just another state. Your state controlling code will get the next state from the menu (in your case the function to call using a function pointer), store it, kill the main menu, and then execute the stored function. \$\endgroup\$ – usm Oct 27 '14 at 6:18
  • \$\begingroup\$ Not sure about what a state machine is (I'm kinda new but not too much) but I think that might (*must) work. I'll do some research and see if it's what I think it is. \$\endgroup\$ – user3195897 Oct 27 '14 at 6:41
2
\$\begingroup\$

First, the answer to your direct question which is whether threads continue running when the main() thread ends can be found at this Stack Overflow answer:

https://stackoverflow.com/a/4667273/377922

when the main thread (that is, the thread that runs the main() function) terminates [...] the process terminates and all other threads stop.

So, as long as you continue running your main game loop, the other threads will continue to run until they end. This might take some re-factoring of your loop, because you are jumping out of it and quitting the whole game.

However, I would strongly discourage you from doing that, because using multiple threads without a really good reason will add an added dimension of complexity. Debugging multiple threads on the same data can be tricky at best and can cause performance problems by trying to avoid writing over data.

I would recommend using a state machine to control your state transitions. I'm not well versed in C, so I'll give you some (object oriented) pseudocode instead:

while (quit == false)
{
    currentState->update();
    // Returns an enum of the state type.
    enum StateType newState = currentState->getNewState();

    if (currentState != newState)
    {
        currentState->cleanUp();
        // Creates the appropriate state from the given enum value.
        currentState = createStateObject(newState);
        currentState->initialise();
    }
    currentState->render();
}

In getNewState() you should return an enum value the state that you want to transition to, based on the user input in the update() function. I suggest using an enum value instead of the raw function pointer to keep your files and include statements a bit tidier.

In your particular example initialise(), is where you'd put the contents of Load_menu_stuff_to_memory(), update() will contain the if...else clause and cleanUp() will contain the contents of Deallocate_menu_stuff(). Of course in C you'd have groups of plain functions for each state, e.g. main_menu_update() and main_menu_render().

One last thing is that it's possible to make currentState a stack of states, each with render and input flags so that in future you can overlay stacks, for a pause menu or running your game in "demo mode" with the main menu drawn on top.

\$\endgroup\$
1
\$\begingroup\$

You could use an "event/task buffer/queue" to produce this behavior.

tl;dr: think of a main loop and a task array; the first task is initializing the menu which in turn will allow the user to activate a task that initializes the game. When a task is over, you return to this main loop, so all the resources that were used by the task, could be safely destroyed and freed from memory. The new task is queued by the menu before the menu is destroyed and then started when you get back to the main loop. You may also wish to use threads if you need to run the menu and the game simultaneously in the future.

In the main() allocate the "event buffer/task queue" and fire the starting event init_menu, then go into the main loop that"ll check if there is a pending or currently active event, if not, then end the loop and the process. Since there is an init_menu event, the loop calls the init_menu_func and the menu starts up. You are now running the menu in it's own thread or in the main thread; when someone chooses an option, the menu adds the correct event/task to the buffer, in this case init_game. The menu task removes itself from the active events buffer,exits it's loop and terminates, freeing all resources.

The main loop is now active and it checks if there is a pending event as usual, it then activates the init_game event and the game starts.

\$\endgroup\$
  • \$\begingroup\$ Not sure but I think you say I should create only one loop for the entire game instead of each function . And run the menu function every frame to see if the user selected another thing to do. If it did execute that function instead of the menu until the user selects other and do the same again \$\endgroup\$ – user3195897 Oct 27 '14 at 6:37
  • \$\begingroup\$ Not really, what are you using for gui right now? What I'm saying is that depending or your architecture, you could have a "main loop" and a "task/event/state - buffer/queue" and add a new task to it before the current task is ending. The main loop will make sure that a new task will start after the current one ended and freed its resources. \$\endgroup\$ – wolfdawn Oct 27 '14 at 6:43
  • \$\begingroup\$ @usm is basically suggesting the same thing, just replace task/event with state or what not. \$\endgroup\$ – wolfdawn Oct 27 '14 at 6:46
  • 1
    \$\begingroup\$ Kinda get it, it would be like getting the new action I want to perform, and add it to something else that will be in scope after the menu function finishes, and when it does I can just execute the action I stored based on the input. That I guess will be on a loop to check every time the current action finishes. \$\endgroup\$ – user3195897 Oct 27 '14 at 6:51
  • \$\begingroup\$ You and @usm both answered my question so I'm gonna flip a coin and mark the winner's answer as the one which answered my question. :D \$\endgroup\$ – user3195897 Oct 27 '14 at 7:03
1
\$\begingroup\$
#include stdio.h

//Author: Coty Embry 
/*  Program Comment: first and foremost im assuming you know how to code in c (to an extent):
    I would say to go at it like a showmenu that is a subprogram
    (think boolean value) which will show the menu, do what 
    you need, then release the memory. Once it accomplishes 
    what you need it to then send back the info you need then 
    release the memory 
    <2 Timothy 2:15>
*/

//I know im going a little different direction than you did in your example by using a switch statement, but anyways lets get to it:
    int menu(int); //this declares that there is going to be a menu

int main(void) {
    select = showmenu();
    switch(select) { //here the program switches to select (which is what the menu function will return) - hopefully you follow what i mean
        case 1: //if menu returns an int that == 1 //TODO (i.e. write your code!! lol) - 
        case 2: //TODO
        //so on and so forth
    }

//this is the subprogram    
int showmenu(void) {
    //here is where the magic happens (im answering you question - hopefully)
    /*  so to resolve you're issue I think the best thing to do here is to
        declare a variable then assign what you need to, free the memory, 
        THEN return what you need
    */
    int whatyouneed; //sorry, but the variable name felt appropriate lol
    //TODO
    //printf("enter what you need and press enter\n");
    scanf("%d", & whatyouneed); //check to make sure syntax is correct
    //now free your memory or whatever you need to do
    Deallocate_Menu_stuff();
    //honestly not sure if you even need to free your memory - this function shouldn't
    //take much memory...but to make the program better i guess it could help in the overall scheme. im not sure to be honest, just speculating
    return whatyouneed; //returns the data you wanted and exits the menu subprogram

    //doing this basically makes it where the only "memory" that is used is the memory used to store that one variable

}
\$\endgroup\$
  • \$\begingroup\$ Thank you, I already had an answer for this, which is marked, I think it is more powerful and simple, anyway in the early days I would have used a method like this one. \$\endgroup\$ – user3195897 Jan 6 '15 at 17:37
  • \$\begingroup\$ I see, okay, thank you for the feedback! Best wishes in all that you do! \$\endgroup\$ – Coty Embry Jan 6 '15 at 18:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.