I have been trying to wrap my head around threads and I have come up with two questions:
1. Is there a way to send events from one thread to another? In particular user events, so that I can send costum information(name of button pressed, upgrade used, etc.). I was thinking of having an event queue in the shared data class which would listen to such user events.
2. Is it possible to use functions of an object as the main function of a thread? I could than have a AI::Think function which would try to find the other player's cannons etc.
Also, according to this thread, threading can make modularising your application way easier if you got the mutexes right. Did I understand that correctly?
Any help?
1. Send them all to a 'global' queue. "Listening" is a big word.
2. With Boost maybe? No, otherwise.
I don't know what the link is about. Just fiddle around until you understand it
Send them all to a 'global' queue.
How do you mean? What I thought of doing was having an event queue in a data class(where you can put a mutex on) and sending costum events to it so that the parent thread can get informed about what happened.
Example of usage:
1. Game initialisation
2. Main thread starts AI thread
3. AI thinks while main thread is handling user input etc.
4. AI wants to make a move and sends an event with all necessary data in it to the event queue in the data class
5. main thread listens to the event queue(how should this happen? there is always the possibility of a mutex being on the queue at the time) in the data class and reacts accordingly by making the move.
6. Go back to step 3
Yes, I believe event queues were explicitly designed to be thread safe. So you can send events from one thread and receive events in another.
I just came up with this to let this happen:
in the data class, I should have an ALLEGRO_USER_EVENT_SOURCE* member, which is set when the thread first starts. Then, in the main thread, I register this event source in the event queue of the main thread, and whenever the AI makes its move, it uses al_emit_user_event to notify the main thread it made a move.
Is my logic sound/should this work?
Yup, though you may also have the option of emitting fake input events. Which ever works best for your case.
I think the AI will want to just say what he wants to do, instead of faking a mouse click or something like that. I'm also thinking of putting user input in another thread with the same principle: as soon as the player really chooses to send a unit(scout,bomb,other upgrade) to the field, the main thread will be noticed trough a user event.
Some people prefer to simulate input events for AI, so it can be recorded in the same way user input is recorded, for replays, save games, and cheat detection. But I think if you're emitting user events for the player as well, you can use those to do all that instead of raw input.
Yeah... I think it is easier to let the user input thread figure out what the user wants to do and then send the corresponding event to the main thread. Otherwise, I would have to put extra code in at the AI output part to calculate all the coordinates of mouse clicks etc.
One technical question that still hasn't been answered: How do I make a function pointer to a member function? Because that's what I'll need if I want to use the AI's Think() function as main function of the thread.
2. Is it possible to use functions of an object as the main function of a thread? I could than have a AI::Think function which would try to find the other player's cannons etc.
Yes, you can use class methods, they just have to be static, and you have to bind the parameters somehow.
Thanks! I'll try that.
EDIT:
This is what I've come up with so far:
These are classes you should derive from, like this:
Or am I doing something terribly wrong here?
Some people prefer to simulate input events for AI, so it can be recorded in the same way user input is recorded, for replays, save games, and cheat detection.
Err, what? I've never heard of that before.
Even if you did do that, how would you prevent the user input from affecting the AI player?
IIRC that's how they did it in Quake, all actors have the same input interface, some are controlled by AI.
Even if you did do that, how would you prevent the user input from affecting the AI player?
The AI is essentially just another player with access to no more control or information as the player is.
Okay, but why would you simulate input events? How would you prevent the user from making those same inputs, thereby screwing wth the AI?
The "inputs" to an actor are just software interfaces, not actually hardwired to the mouse or anything.
Yes, but TF was talking about emitting fake input events. If you're faking input events to control the AI, then it looks the same as normal input events.
The AI actors inputs are sent "events" by the AI. Your protagonist actor is sent "events" from the mouse and keyboard, etc.
Think of a computer controlled car that has servos hooked to the steering wheel and pedals, and you're not in it. You race this car by driving another car normally.
Yes, but TF was talking about emitting fake input events. If you're faking input events to control the AI, then it looks the same as normal input events.
Depends. If you went that low level, you could simulate a second mouse/keyboard. But "Input Events" does not necessarily mean low level input events. But yeah, if Allegro doesn't have a way to distinguish between multiple low level input devices, that would make it difficult to go that low level.
Yes, I understand. I am questioning TF's solution of handling threading by putting fake input events into the queue from the other thread.
This:
But "Input Events" does not necessarily mean low level input events
It's not a very hard concept to grasp.
The original description was ambiguous at best, and that was what I was referring to. I understand the intended meaning...
Some people prefer to simulate input events for AI, so it can be recorded in the same way user input is recorded, for replays, save games, and cheat detection.
I don't think you would put them on the same queue. For example, you could have an Entity class that has a ALLEGRO_EVENT *GetInput(void) method that could return ALLEGRO_EVENTS like key presses and releases and the "Game" class would handle them. Then you can do things like:
for (i = 0; i < num_entities; i++) { ALLEGRO_EVENT *e = entity[i]->GetInput(); if (e) { if (e->type == ALLEGRO_EVENT_KEYBOARD) { switch (e->keyboard.keycode) { ... } } } }
And you could have some typedef:
typedef ALLEGRO_EVENT *(input_getter)(void);
Then your player class could have
private:
input_getter input;
And when you wanted to change input you could just set 'input' to PhysicalInput(), ScriptInput(), NoInput() or whatever.
None of this really relies on using ALLEGRO_EVENTs though. But generally having a standard interface to get input from can be useful.
The original description was ambiguous at best, and that was what I was referring to. I understand the intended meaning...
It was meant to cover both low level injecting, and using higher level events, but both would still be input simulation as far as the engine is concerned.
Bugfix: The code I posted had 2 errors, which are fixed in this renewed code:
EDIT: about input, I'm thinking of making costum events for using upgrades(scout,bomb,tunneler,...) so that those can be sent to the main game logic thread instead of raw input. I'll let the UI thread find out which upgrade the player wants to place where.(High-level input FTW )
EDIT2: Are allegro calls thread-safe?(Like al_get_display_width/height,...)
I also have a threading related question. Guess I'll just ask it here:
When should I use mutexes? I know you're supposed to use them when, for example, accessing linked lists or something similiar. However, somewhere I read that you have to use them even when you're just using shared variables or even shared functions. Is that correct? I can hardly imagine, because that would surely make a lot of mutexes.
Also can someone here recommend good thread setups? Right now I have one thread for the logic loop and one thread for the screen loop. For a simple 2D platformer like I'm making, I guess, that's alright, although I'm only using up to two cores, but generally speaking: Is there any recommended thread setup for games? How many threads should you use and what for?
Are allegro calls thread-safe?
Yes and no. It's not documented, and I'm not even sure which calls are and aren't. Other than events, you should basically assume the calls are not thread safe.
Guess I'll just ask it here:
Don't hijack other people's threads.
Don't hijack other people's threads.
I don't see the problem, as it's perfectly related to the thread's title and can most likely help the thread creator as well. If you still think my post doesn't fit then tell me and I'll create a new one.
To answer your question:
AFAIK the only time you need to use mutexes is when there's the possibility two threads will try to access the same variable at the same time. That's the whole point of mutexes and conditions.
I didn't know that you need them when accessing lists etc... seems strange.
EDIT: about thread setup, I was thinking of doing it this way:
Main thread where the game logic is executed
User input thread
AI thread
Render thread
The UI and AI threads send costum events to the main thread, which I explained before.
Thanks for the response.
AFAIK the only time you need to use mutexes is when there's the possibility two threads will try to access the same variable at the same time. That's the whole point of mutexes and conditions.
I didn't know that you need them when accessing lists etc... seems strange.
Well, if accessing linked lists (talking about shared lists here of course) without a mutex, one thread could delete an element another thread is using, causing it to be deadlocked, so it seems logical to me to use a mutex in this situation. I just don't know if using regular shared variables necessarily requires mutexes. Is it that critical if two threads access a variable at the same time? Sure: When using a variable multiple times in a thread it may be a good idea to make a copy of it, anyways, just to prevent it from being changed mid-thread, but let's assume we have a variable that the logic thread writes to, while the render thread only reads it. Can it have critical effects if both threads access the variable at the same time, anyways?
If the render thread asks for it while the logic thread is changing it, yes(certainly for larger variables). You could get garbage values because the processor is halfway trough its writing process.
I see. I guess it's "rather be safe than sorry" then and I shouldn't hesitate to use mutexes. Thanks!
You can also go too crazy using mutexes (mutices?[1]). Balance is key.
I'm working on solving a race condition[2] at the moment, which can happen with overuse of mutexes. In my particular case there is design flaw causing the mutex to try to lock itself twice. For instance:
In this case the oracle must consult his adviser to give his answer. Little does the Oracle know, the adviser has a buddy. The adviser always consults his buddy before telling the oracle what to do. When the buddy is unsure what to give the adviser, he consults the oracle.
Here is the backtrace (flipped for learner's sake):
printf() <- The output statement
theOracle() => the mutex is now locked!
adviser() <- the oracle is consulting his adviser
theAdvisersBuddy() <- the adviser is consulting his buddy
theOracle() => The mutex is locked a second time!
Since you can't lock a mutex twice, the program will freeze on the line 'mutex.lock()' inside theOracle.
Can't recursive mutexes do that (assuming all that code is running on one thread)?
I suppose that's true. My example is not ideal then.