|
This thread is locked; no one can reply to it. |
1
2
|
Allegro 5 Threading Interface |
AMCerasoli
Member #11,955
May 2010
|
Hi guys, One of the libCurl function is synchronous (which means you can't continue until the function has completed one way or another). So I would need to do some multi-thread to avoid pausing the entire game while requesting the data from the server. I have being checking the example (too elaborated to be actually an example) to understand the Allegro thread interface. But what I would like to do is just open a new thread, modified some variables (std::string) and then close it. My question is: If I create a variable called std::string string, outside of the tread, then send the address of that variable and use a pointer to modified that variable in the thread, but at the same time I might be using it (not modifying it) the variable outside the thread, do I need to use mutex and things like that? Does someone have really an example to show a very basic program using the Allegro 5 threading interface? Thanks.
|
Vanneto
Member #8,643
May 2007
|
Check out the multi interface. In capitalist America bank robs you. |
Matthew Leverton
Supreme Loser
January 1999
|
AMCerasoli said: If I create a variable called std::string string, outside of the tread, then send the address of that variable and use a pointer to modified that variable in the thread, but at the same time I might be using it (not modifying it) the variable outside the thread, do I need to use mutex and things like that? Yes. Why don't you create a little example using libcurl and an Allegro thread and then post it here for comments? |
AMCerasoli
Member #11,955
May 2010
|
Quote: Check out the multi [curl.haxx.se] interface. It says: 1. Enable a "pull" interface. The application that uses libcurl decides where and when to ask libcurl to get/send data. 2. Enable multiple simultaneous transfers in the same thread without making it complicated for the application. 3. Enable the application to wait for action on its own file descriptors and curl's file descriptors simultaneous easily. There is no multi-thread. Besides I don't need multi handle since I'm doing just one call to the server to just one specific file. I don't need to retrieve nor check multiple calls to server. Matthew Leverton said: Why don't you create a little example using libcurl and an Allegro thread and then post it here for comments? Here, and probably the wiki, and probably should be inside the examples binaries too. there is thread.c and thread2.c and as the name says (thread2.c) it's even more elaborated, with more functions, structs, and unfortunately the mutex thing. Sorry but there is nothing you could do right now, I'm going to still struggling with thread2.c file to get to the point. I just wanted to know if I had to use mutex because without using it I already know how to do it, but using the mutex thing I have no Idea, I'm going to have to read more.
|
Matthew Leverton
Supreme Loser
January 1999
|
Assuming you have some variable named foo that is shared, you can do something like this: // call this once at the beginning ALLEGRO_MUTEX *m = al_create_mutex(); // within the various threads, do this any time you want to access the variable al_lock_mutex(m); // use variable foo al_unlock_mutex(m); // call this once at the very end al_destroy_mutex(m);
|
AMCerasoli
Member #11,955
May 2010
|
Ok, thanks Matt, that helps me solve my particular problem, don't know if I'm doing it correct, though. But I'm trying to create a little example to put it on the Wiki, but I don't know if I'm using the functions correctly. I took a Wiki tut and modified a little bit. Concept: Change the X axis in one thread and the Y axis in another thread of a bitmap. 1#include <stdio.h>
2#include <iostream>
3#include <allegro5/allegro.h>
4
5class DATA{
6
7 public:
8 float posiX;
9 float posiY;
10 bool modi_X;
11
12 DATA(){
13
14 posiX = 0;
15 posiY = 0;
16 modi_X = false;
17
18 }
19
20}data;
21
22const float FPS = 60;
23const int SCREEN_W = 640;
24const int SCREEN_H = 480;
25const int BOUNCER_SIZE = 32;
26
27static void *Func_Thread(ALLEGRO_THREAD *thr, void *arg);
28
29int main(int argc, char **argv)
30{
31 ALLEGRO_DISPLAY *display = NULL;
32 ALLEGRO_EVENT_QUEUE *event_queue = NULL;
33 ALLEGRO_TIMER *timer = NULL;
34 ALLEGRO_BITMAP *bouncer = NULL;
35 ALLEGRO_MUTEX *mutex = NULL;
36 ALLEGRO_THREAD *thread_1 = NULL;
37 ALLEGRO_THREAD *thread_2 = NULL;
38
39 bool redraw = true;
40
41 if(!al_init()) {
42 fprintf(stderr, "failed to initialize allegro!\n");
43 return -1;
44 }
45
46 if(!al_install_mouse()) {
47 fprintf(stderr, "failed to initialize the mouse!\n");
48 return -1;
49 }
50
51 timer = al_create_timer(1.0 / FPS);
52 if(!timer) {
53 fprintf(stderr, "failed to create timer!\n");
54 return -1;
55 }
56
57 display = al_create_display(SCREEN_W, SCREEN_H);
58 if(!display) {
59 fprintf(stderr, "failed to create display!\n");
60 al_destroy_timer(timer);
61 return -1;
62 }
63
64 bouncer = al_create_bitmap(BOUNCER_SIZE, BOUNCER_SIZE);
65 if(!bouncer) {
66 fprintf(stderr, "failed to create bouncer bitmap!\n");
67 al_destroy_display(display);
68 al_destroy_timer(timer);
69 return -1;
70 }
71
72 al_set_target_bitmap(bouncer);
73
74 al_clear_to_color(al_map_rgb(255, 0, 255));
75
76 al_set_target_bitmap(al_get_backbuffer(display));
77
78 event_queue = al_create_event_queue();
79
80 if(!event_queue) {
81 fprintf(stderr, "failed to create event_queue!\n");
82 al_destroy_bitmap(bouncer);
83 al_destroy_display(display);
84 al_destroy_timer(timer);
85 return -1;
86 }
87
88 al_register_event_source(event_queue, al_get_display_event_source(display));
89 al_register_event_source(event_queue, al_get_timer_event_source(timer));
90 al_register_event_source(event_queue, al_get_mouse_event_source());
91 al_clear_to_color(al_map_rgb(0,0,0));
92 al_flip_display();
93 al_start_timer(timer);
94
95 mutex = al_create_mutex();
96
97 thread_1 = al_create_thread(Func_Thread, &data);
98 al_start_thread(thread_1);
99
100 al_rest(1); //Why without this doesn't work?
101
102 al_lock_mutex(mutex);
103 data.modi_X = true;
104 al_unlock_mutex(mutex);
105
106
107 thread_2 = al_create_thread(Func_Thread, &data);
108 al_start_thread(thread_2);
109
110
111 while(1)
112 {
113 ALLEGRO_EVENT ev;
114 al_wait_for_event(event_queue, &ev);
115
116 if(ev.type == ALLEGRO_EVENT_TIMER) {
117 redraw = true;
118 }
119 else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
120 break;
121 }
122 else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
123 Beep(500,20);
124 }
125 if(redraw && al_is_event_queue_empty(event_queue)) {
126 redraw = false;
127
128 //al_clear_to_color(al_map_rgb(0,0,0));
129
130 al_lock_mutex(mutex);
131 al_draw_bitmap(bouncer, data.posiX, data.posiY, 0);
132 al_unlock_mutex(mutex);
133
134 al_flip_display();
135 }
136 }
137
138 al_destroy_bitmap(bouncer);
139 al_destroy_timer(timer);
140 al_destroy_display(display);
141 al_destroy_event_queue(event_queue);
142
143 return 0;
144}
145
146 static void *Func_Thread(ALLEGRO_THREAD *thr, void *arg){
147
148 ALLEGRO_MUTEX *mutex;
149 mutex = al_create_mutex();
150
151 DATA *data = (DATA*) arg;
152
153 float num = 0.1;
154 bool modi_X = data->modi_X;
155
156
157
158 while(1){
159
160 al_lock_mutex(mutex);
161
162 if(!modi_X)
163 data->posiX += num;
164 else
165 data->posiY += num;
166
167 al_rest(0.01); // If I don't use this, I'm not seeing the image because I'm adding 'num' too fast?
168
169 al_unlock_mutex(mutex);
170 }
171
172
173 return NULL;
174 }
Well, there are some comments on the source about things that I can't understand, all the thread thing it's very new for me but I think it's incredible powerful. I was also trying to add the feature, to allow the user to start or stop the movement of the bitmap, but I think I need conditionals, because suppose that I have a bool called run inside DATA I can't do something like this: while(data->run){ if(!modi_X) data->posiX += num; else data->posiY += num; } So for easy answers: 1) So in the first code comment when I said "//Why without this doesn't work?" why is that happening? why without al_rest() the data info is sent incorrectly? it's because takes more time to change data.modi_X = true than create a new thread, so the new thread receive the old data? 2) In the second comment "//If I don't use this, I'm not seeing the image because I'm adding 'num' too fast?" I guess that is because even before allegro create the windows this thread is created and the num variable increase its value too fast? and why if instead of add 0.1 I add 0.000001 and delete the al_rest() line just works for some steps and then do nothing? 3) Can I call al_destroy_thread() inside the same thread? I'm using that in my code (not this one, here I'm not destroying the threads yet) but I don't know if is doing something... I have no error. 4) To check if a struct or class variable has change do I need to use conditionals? Damn, this looks like a FAQ...
|
Matthew Leverton
Supreme Loser
January 1999
|
Just a couple of things quickly:
|
weapon_S
Member #7,859
October 2006
|
Arthur Kalliokoski
Second in Command
February 2005
|
The 'volatile' keyword simply means the compiler shouldn't optimize code that uses that variable, for instance the timer tick, the compiler could just load a copy into eax and wait forever to see if it changes all by itself (and the timer thread could hardly be expected to do that). They all watch too much MSNBC... they get ideas. |
AMCerasoli
Member #11,955
May 2010
|
Ok ,I have modified the code: Now I'm destroying the thread at the end of the program, and initializing mutex inside the class data. But most of my questions still there, though. 1#include <stdio.h>
2#include <iostream>
3#include <allegro5/allegro.h>
4
5class DATA{
6
7 public:
8 ALLEGRO_MUTEX *mutex;
9 float posiX;
10 float posiY;
11 bool modi_X;
12
13 DATA(){
14
15 mutex = al_create_mutex();
16 posiX = 0;
17 posiY = 0;
18 modi_X = false;
19
20 }
21
22}data;
23
24const float FPS = 60;
25const int SCREEN_W = 640;
26const int SCREEN_H = 480;
27const int BOUNCER_SIZE = 32;
28
29static void *Func_Thread(ALLEGRO_THREAD *thr, void *arg);
30
31int main(int argc, char **argv)
32{
33 ALLEGRO_DISPLAY *display = NULL;
34 ALLEGRO_EVENT_QUEUE *event_queue = NULL;
35 ALLEGRO_TIMER *timer = NULL;
36 ALLEGRO_BITMAP *bouncer = NULL;
37 ALLEGRO_THREAD *thread_1 = NULL;
38 ALLEGRO_THREAD *thread_2 = NULL;
39
40 bool redraw = true;
41
42 if(!al_init()) {
43 fprintf(stderr, "failed to initialize allegro!\n");
44 return -1;
45 }
46
47 if(!al_install_mouse()) {
48 fprintf(stderr, "failed to initialize the mouse!\n");
49 return -1;
50 }
51
52 timer = al_create_timer(1.0 / FPS);
53 if(!timer) {
54 fprintf(stderr, "failed to create timer!\n");
55 return -1;
56 }
57
58 display = al_create_display(SCREEN_W, SCREEN_H);
59 if(!display) {
60 fprintf(stderr, "failed to create display!\n");
61 al_destroy_timer(timer);
62 return -1;
63 }
64
65 bouncer = al_create_bitmap(BOUNCER_SIZE, BOUNCER_SIZE);
66 if(!bouncer) {
67 fprintf(stderr, "failed to create bouncer bitmap!\n");
68 al_destroy_display(display);
69 al_destroy_timer(timer);
70 return -1;
71 }
72
73 al_set_target_bitmap(bouncer);
74
75 al_clear_to_color(al_map_rgb(255, 0, 255));
76
77 al_set_target_bitmap(al_get_backbuffer(display));
78
79 event_queue = al_create_event_queue();
80
81 if(!event_queue) {
82 fprintf(stderr, "failed to create event_queue!\n");
83 al_destroy_bitmap(bouncer);
84 al_destroy_display(display);
85 al_destroy_timer(timer);
86 return -1;
87 }
88
89 al_register_event_source(event_queue, al_get_display_event_source(display));
90 al_register_event_source(event_queue, al_get_timer_event_source(timer));
91 al_register_event_source(event_queue, al_get_mouse_event_source());
92 al_clear_to_color(al_map_rgb(0,0,0));
93 al_flip_display();
94 al_start_timer(timer);
95
96 thread_1 = al_create_thread(Func_Thread, &data);
97 al_start_thread(thread_1);
98
99 al_rest(1); //Why without this doesn't work?
100
101 al_lock_mutex(data.mutex);
102 data.modi_X = true;
103 al_unlock_mutex(data.mutex);
104
105
106 thread_2 = al_create_thread(Func_Thread, &data);
107 al_start_thread(thread_2);
108
109
110 while(1)
111 {
112 ALLEGRO_EVENT ev;
113 al_wait_for_event(event_queue, &ev);
114
115 if(ev.type == ALLEGRO_EVENT_TIMER) {
116 redraw = true;
117 }
118 else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
119 break;
120 }
121 else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
122 Beep(500,20);
123 }
124 if(redraw && al_is_event_queue_empty(event_queue)) {
125 redraw = false;
126
127 //al_clear_to_color(al_map_rgb(0,0,0));
128
129 al_lock_mutex(data.mutex);
130 al_draw_bitmap(bouncer, data.posiX, data.posiY, 0);
131 al_unlock_mutex(data.mutex);
132
133 al_flip_display();
134 }
135 }
136 al_destroy_thread(thread_1);
137 al_destroy_thread(thread_2);
138
139 al_destroy_bitmap(bouncer);
140 al_destroy_timer(timer);
141 al_destroy_display(display);
142 al_destroy_event_queue(event_queue);
143
144 return 0;
145}
146
147 static void *Func_Thread(ALLEGRO_THREAD *thr, void *arg){
148
149 DATA *data = (DATA*) arg;
150
151 float num = 0.1;
152 bool modi_X = data->modi_X;
153
154 while(!al_get_thread_should_stop(thr)){
155
156 al_lock_mutex(data->mutex);
157
158 if(!modi_X)
159 data->posiX += num;
160 else
161 data->posiY += num;
162
163 al_rest(0.01); // If I don't use this, I'm not seeing the image because I'm adding 'num' too fast?
164
165 al_unlock_mutex(data->mutex);
166 }
167
168
169 return NULL;
170 }
Here are some Images about what happens on different processors: AMD Turion 64X2 (2 processors) Intel P4 (1 processor) Intel Atom N450 (1 processor, and 2 threads? that is what says the webpage) I'm still thinking why I'm getting those results.
|
Elias
Member #358
May 2000
|
You can't create your data object before main() because Allegro functions (like al_create_mutex) must not be called before al_init. -- |
weapon_S
Member #7,859
October 2006
|
First of all I'm using this as an excuse to look into threading ( I don't know shit ) AMCerasoli said: al_rest(1); //Why without this doesn't work? My guess: both threads will be set to modiX = true; Quote: al_rest(0.01); // If I don't use this, I'm not seeing the image because I'm adding 'num' too fast? That comment seems very correct. By the way, there is a nice optical illusion in the last one. (In fact it is not impossible). |
AMCerasoli
Member #11,955
May 2010
|
Damn! you hit the nail weapon_S!! I was overlooking that, now in all computers shows the same, like the P4 picture, Except if I open another program in which I can see a very little variation in the image. weapon_S said: My guess: both threads will be set to modiX = true; Yes I know that, the question is, why? And my only answer is: because takes more time to change data.modi_X to true than create a new thread, so the new thread receive the old data? Here is the last update. 1#include <stdio.h>
2#include <iostream>
3#include <allegro5/allegro.h>
4
5class DATA{
6
7 public:
8 ALLEGRO_MUTEX *mutex;
9 float posiX;
10 float posiY;
11 bool modi_X;
12
13 DATA(){
14
15 mutex = al_create_mutex();
16 posiX = 0;
17 posiY = 0;
18 modi_X = false;
19
20 }
21
22};
23
24const float FPS = 60;
25const int SCREEN_W = 640;
26const int SCREEN_H = 480;
27const int BOUNCER_SIZE = 32;
28
29static void *Func_Thread(ALLEGRO_THREAD *thr, void *arg);
30
31int main(int argc, char **argv)
32{
33 ALLEGRO_DISPLAY *display = NULL;
34 ALLEGRO_EVENT_QUEUE *event_queue = NULL;
35 ALLEGRO_TIMER *timer = NULL;
36 ALLEGRO_BITMAP *bouncer = NULL;
37 ALLEGRO_THREAD *thread_1 = NULL;
38 ALLEGRO_THREAD *thread_2 = NULL;
39
40 bool redraw = true;
41
42 if(!al_init()) {
43 fprintf(stderr, "failed to initialize allegro!\n");
44 return -1;
45 }
46
47 if(!al_install_mouse()) {
48 fprintf(stderr, "failed to initialize the mouse!\n");
49 return -1;
50 }
51
52 timer = al_create_timer(1.0 / FPS);
53 if(!timer) {
54 fprintf(stderr, "failed to create timer!\n");
55 return -1;
56 }
57
58 display = al_create_display(SCREEN_W, SCREEN_H);
59 if(!display) {
60 fprintf(stderr, "failed to create display!\n");
61 al_destroy_timer(timer);
62 return -1;
63 }
64
65 bouncer = al_create_bitmap(BOUNCER_SIZE, BOUNCER_SIZE);
66 if(!bouncer) {
67 fprintf(stderr, "failed to create bouncer bitmap!\n");
68 al_destroy_display(display);
69 al_destroy_timer(timer);
70 return -1;
71 }
72
73 al_set_target_bitmap(bouncer);
74 al_clear_to_color(al_map_rgb(255, 0, 255));
75 al_set_target_bitmap(al_get_backbuffer(display));
76 event_queue = al_create_event_queue();
77
78 if(!event_queue) {
79 fprintf(stderr, "failed to create event_queue!\n");
80 al_destroy_bitmap(bouncer);
81 al_destroy_display(display);
82 al_destroy_timer(timer);
83 return -1;
84 }
85
86 al_register_event_source(event_queue, al_get_display_event_source(display));
87 al_register_event_source(event_queue, al_get_timer_event_source(timer));
88 al_register_event_source(event_queue, al_get_mouse_event_source());
89 al_clear_to_color(al_map_rgb(0,0,0));
90 al_flip_display();
91 al_start_timer(timer);
92
93 DATA data;
94
95 thread_1 = al_create_thread(Func_Thread, &data);
96 al_start_thread(thread_1);
97
98 al_rest(1); //Why without this doesn't work?
99
100 al_lock_mutex(data.mutex);
101 data.modi_X = true;
102 al_unlock_mutex(data.mutex);
103
104 thread_2 = al_create_thread(Func_Thread, &data);
105 al_start_thread(thread_2);
106
107
108 while(1)
109 {
110 ALLEGRO_EVENT ev;
111 al_wait_for_event(event_queue, &ev);
112
113 if(ev.type == ALLEGRO_EVENT_TIMER) {
114 redraw = true;
115 }
116 else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
117 break;
118 }
119 else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
120 Beep(500,20);
121 }
122 if(redraw && al_is_event_queue_empty(event_queue)) {
123 redraw = false;
124
125 //al_clear_to_color(al_map_rgb(0,0,0));
126
127 al_lock_mutex(data.mutex);
128 al_draw_bitmap(bouncer, data.posiX, data.posiY, 0);
129 al_unlock_mutex(data.mutex);
130
131 al_flip_display();
132 }
133 }
134 al_destroy_thread(thread_1);
135 al_destroy_thread(thread_2);
136
137 al_destroy_bitmap(bouncer);
138 al_destroy_timer(timer);
139 al_destroy_display(display);
140 al_destroy_event_queue(event_queue);
141
142 return 0;
143}
144
145 static void *Func_Thread(ALLEGRO_THREAD *thr, void *arg){
146
147 DATA *data = (DATA*) arg;
148
149 float num = 0.1;
150 bool modi_X = data->modi_X;
151
152 while(!al_get_thread_should_stop(thr)){
153
154 al_lock_mutex(data->mutex);
155
156 if(!modi_X)
157 data->posiX += num;
158 else
159 data->posiY += num;
160
161 al_unlock_mutex(data->mutex);
162
163 al_rest(0.1);
164
165 }
166
167 return NULL;
168 }
|
weapon_S
Member #7,859
October 2006
|
AMCerasoli said: And my only answer is: because takes more time to change data.modi_X to true than create a new thread, so the new thread receive the old data? When you don't insert that rest, the modi_X gets changed before the other thread reaches line 152. Whenever you are reading/writing shared data you should mutex[1]. So that would also go for reading/writing modi_X. References
|
AMCerasoli
Member #11,955
May 2010
|
I still don't get it 1
2 DATA data;
3
4 thread_1 = al_create_thread(Func_Thread, &data); //Here I send data with modi_X
5 al_start_thread(thread_1); //as false
6
7 //al_rest(1);
8
9 al_lock_mutex(data.mutex);
10 data.modi_X = true; //Here I change the value (using correctly the
11 al_unlock_mutex(data.mutex); //Mutual thingy)
12
13 thread_2 = al_create_thread(Func_Thread, &data); //Then here I should send
14 al_start_thread(thread_2); //data with the modi_X already
15 //modified. But if don't use
16 //rest that doesn't happens.
If what you say is true: "When you don't insert that rest, the modi_X gets changed before the other thread reaches line 152." shouldn't work correctly? I think what it's happening is that if I don't insert that rest, the modi_X gets changed after the other thread reaches line 152. Isn't that right?
|
Matthew Leverton
Supreme Loser
January 1999
|
It would need to be something like this: Parent Thread
Child Thread #1
Child Thread #2
Here's a sample program: 1#include <allegro5/allegro.h>
2#include <stdio.h>
3
4typedef struct threaddatatag {
5 ALLEGRO_MUTEX *m;
6 ALLEGRO_COND *c;
7 int x;
8 bool ready;
9} THREAD_DATA;
10
11void *child_thread(ALLEGRO_THREAD *me, void *param)
12{
13 THREAD_DATA *data = param;
14 int x;
15
16 printf("Child thread running!\n");
17
18 al_lock_mutex(data->m);
19 al_rest(1);
20 x = data->x;
21 data->ready = true;
22 al_broadcast_cond(data->c);
23 printf("Child signalled that it is ready\n");
24 al_rest(0.10);
25 al_unlock_mutex(data->m);
26
27 printf("x is %d\n", x);
28
29 while (!al_get_thread_should_stop(me))
30 {
31 al_rest(1);
32 }
33
34 return NULL;
35}
36
37int main()
38{
39 ALLEGRO_THREAD *child;
40 THREAD_DATA *data;
41
42 al_init();
43
44 data = malloc(sizeof(*data));
45 data->m = al_create_mutex();
46 data->c = al_create_cond();
47
48 child = al_create_thread(child_thread, data);
49
50 data->ready = false;
51 data->x = 1;
52
53 al_start_thread(child);
54
55 al_lock_mutex(data->m);
56 while (!data->ready)
57 {
58 printf("Parent is waiting for child to be ready\n");
59 al_wait_cond(data->c, data->m);
60 }
61 al_unlock_mutex(data->m);
62
63 // repeat proces for child thread #2
64
65 al_destroy_thread(child);
66
67 return 0;
68}
Note how it uses a signal (condition) along with a "ready" flag that tells the parent that the child has read the x value. |
AMCerasoli
Member #11,955
May 2010
|
oh yhea, now it's working without al_rest(). thread-0.0.3 1
2#include <stdio.h>
3#include <iostream>
4#include <allegro5/allegro.h>
5
6class DATA{
7
8 public:
9
10 ALLEGRO_MUTEX *mutex;
11 ALLEGRO_COND *cond;
12 float posiX;
13 float posiY;
14 bool modi_X;
15
16 DATA(){
17
18 mutex = al_create_mutex();
19 cond = al_create_cond();
20 posiX = 0;
21 posiY = 0;
22 modi_X = false;
23
24 }
25
26 ~DATA(){
27
28 al_destroy_mutex(mutex);
29 al_destroy_cond(cond);
30
31 }
32
33};
34
35const float FPS = 30;
36const int SCREEN_W = 640;
37const int SCREEN_H = 480;
38const int BOUNCER_SIZE = 32;
39
40static void *Func_Thread(ALLEGRO_THREAD *thr, void *arg);
41
42int main(int argc, char **argv)
43{
44 ALLEGRO_DISPLAY *display = NULL;
45 ALLEGRO_EVENT_QUEUE *event_queue = NULL;
46 ALLEGRO_TIMER *timer = NULL;
47 ALLEGRO_BITMAP *bouncer = NULL;
48 ALLEGRO_THREAD *thread_1 = NULL;
49 ALLEGRO_THREAD *thread_2 = NULL;
50
51 bool redraw = true;
52
53 if(!al_init()) {
54 fprintf(stderr, "failed to initialize allegro!\n");
55 return -1;
56 }
57
58 if(!al_install_mouse()) {
59 fprintf(stderr, "failed to initialize the mouse!\n");
60 return -1;
61 }
62
63 timer = al_create_timer(1.0 / FPS);
64 if(!timer) {
65 fprintf(stderr, "failed to create timer!\n");
66 return -1;
67 }
68
69 display = al_create_display(SCREEN_W, SCREEN_H);
70 if(!display) {
71 fprintf(stderr, "failed to create display!\n");
72 al_destroy_timer(timer);
73 return -1;
74 }
75
76 bouncer = al_create_bitmap(BOUNCER_SIZE, BOUNCER_SIZE);
77 if(!bouncer) {
78 fprintf(stderr, "failed to create bouncer bitmap!\n");
79 al_destroy_display(display);
80 al_destroy_timer(timer);
81 return -1;
82 }
83
84 al_set_target_bitmap(bouncer);
85
86 al_clear_to_color(al_map_rgb(255, 0, 255));
87
88 al_set_target_bitmap(al_get_backbuffer(display));
89
90 event_queue = al_create_event_queue();
91
92 if(!event_queue) {
93 fprintf(stderr, "failed to create event_queue!\n");
94 al_destroy_bitmap(bouncer);
95 al_destroy_display(display);
96 al_destroy_timer(timer);
97 return -1;
98 }
99
100 al_register_event_source(event_queue, al_get_display_event_source(display));
101 al_register_event_source(event_queue, al_get_timer_event_source(timer));
102 al_register_event_source(event_queue, al_get_mouse_event_source());
103 al_clear_to_color(al_map_rgb(0,0,0));
104 al_flip_display();
105 al_start_timer(timer);
106
107 DATA data;
108
109 thread_1 = al_create_thread(Func_Thread, &data);
110 al_start_thread(thread_1);
111
112 al_lock_mutex(data.mutex);
113 al_wait_cond(data.cond, data.mutex);
114 al_unlock_mutex(data.mutex);
115
116 al_lock_mutex(data.mutex);
117 data.modi_X = true;
118 al_unlock_mutex(data.mutex);
119
120 thread_2 = al_create_thread(Func_Thread, &data);
121 al_start_thread(thread_2);
122
123
124 while(1)
125 {
126 ALLEGRO_EVENT ev;
127 al_wait_for_event(event_queue, &ev);
128
129 if(ev.type == ALLEGRO_EVENT_TIMER) {
130 redraw = true;
131 }
132 else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
133 break;
134 }
135 else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
136 break;
137 }
138 if(redraw && al_is_event_queue_empty(event_queue)) {
139 redraw = false;
140
141 al_lock_mutex(data.mutex);
142 al_draw_bitmap(bouncer, data.posiX, data.posiY, 0);
143 al_unlock_mutex(data.mutex);
144
145 al_flip_display();
146 }
147 }
148 al_destroy_thread(thread_1);
149 al_destroy_thread(thread_2);
150
151 al_destroy_bitmap(bouncer);
152 al_destroy_timer(timer);
153 al_destroy_display(display);
154 al_destroy_event_queue(event_queue);
155
156 return 0;
157}
158
159 static void *Func_Thread(ALLEGRO_THREAD *thr, void *arg){
160
161 DATA *data = (DATA*) arg;
162 float num = 0.1;
163
164 al_lock_mutex(data->mutex);
165
166 bool modi_X = data->modi_X;
167 al_broadcast_cond(data->cond);
168
169 al_unlock_mutex(data->mutex);
170
171 while(!al_get_thread_should_stop(thr)){
172
173 al_lock_mutex(data->mutex);
174
175 if(modi_X)
176 data->posiX += num;
177 else
178 data->posiY += num;
179
180 al_unlock_mutex(data->mutex);
181
182 al_rest(0.01);
183
184 }
185
186 return NULL;
187 }
Isn't just beautiful? simpler couldn't be (Matt don't do it)...
|
Matthew Leverton
Supreme Loser
January 1999
|
You cannot omit the ready flag because the child might broadcast the signal before the parent is ready to catch it. To test that theory, place a short rest before the parent waits for the signal. If you give the child enough time to initialize, then the parent will get stuck waiting forever. When programming with threads you can never assume the order or speed in which two things in parallel happen. |
AMCerasoli
Member #11,955
May 2010
|
Ok I think now I get it. What do you think? 1
2#include <stdio.h>
3#include <iostream>
4#include <allegro5/allegro.h>
5
6class DATA{
7
8 public:
9
10 ALLEGRO_MUTEX *mutex;
11 ALLEGRO_COND *cond;
12 float posiX;
13 float posiY;
14 bool modi_X;
15 bool ready;
16
17 DATA(){
18
19 mutex = al_create_mutex();
20 cond = al_create_cond();
21 posiX = 0;
22 posiY = 0;
23 modi_X = false;
24 ready = false;
25
26 }
27
28 ~DATA(){
29
30 al_destroy_mutex(mutex);
31 al_destroy_cond(cond);
32
33 }
34
35};
36
37const float FPS = 30;
38const int SCREEN_W = 640;
39const int SCREEN_H = 480;
40const int BOUNCER_SIZE = 32;
41
42static void *Func_Thread(ALLEGRO_THREAD *thr, void *arg);
43
44int main(int argc, char **argv)
45{
46 ALLEGRO_DISPLAY *display = NULL;
47 ALLEGRO_EVENT_QUEUE *event_queue = NULL;
48 ALLEGRO_TIMER *timer = NULL;
49 ALLEGRO_BITMAP *bouncer = NULL;
50 ALLEGRO_THREAD *thread_1 = NULL;
51 ALLEGRO_THREAD *thread_2 = NULL;
52
53 bool redraw = true;
54
55 if(!al_init()) {
56 fprintf(stderr, "failed to initialize allegro!\n");
57 return -1;
58 }
59
60 if(!al_install_mouse()) {
61 fprintf(stderr, "failed to initialize the mouse!\n");
62 return -1;
63 }
64
65 timer = al_create_timer(1.0 / FPS);
66 if(!timer) {
67 fprintf(stderr, "failed to create timer!\n");
68 return -1;
69 }
70
71 display = al_create_display(SCREEN_W, SCREEN_H);
72 if(!display) {
73 fprintf(stderr, "failed to create display!\n");
74 al_destroy_timer(timer);
75 return -1;
76 }
77
78 bouncer = al_create_bitmap(BOUNCER_SIZE, BOUNCER_SIZE);
79 if(!bouncer) {
80 fprintf(stderr, "failed to create bouncer bitmap!\n");
81 al_destroy_display(display);
82 al_destroy_timer(timer);
83 return -1;
84 }
85
86 al_set_target_bitmap(bouncer);
87 al_clear_to_color(al_map_rgb(255, 0, 255));
88 al_set_target_bitmap(al_get_backbuffer(display));
89 event_queue = al_create_event_queue();
90
91 if(!event_queue) {
92 fprintf(stderr, "failed to create event_queue!\n");
93 al_destroy_bitmap(bouncer);
94 al_destroy_display(display);
95 al_destroy_timer(timer);
96 return -1;
97 }
98
99 al_register_event_source(event_queue, al_get_display_event_source(display));
100 al_register_event_source(event_queue, al_get_timer_event_source(timer));
101 al_register_event_source(event_queue, al_get_mouse_event_source());
102 al_clear_to_color(al_map_rgb(0,0,0));
103 al_flip_display();
104 al_start_timer(timer);
105
106 DATA data;
107
108 thread_1 = al_create_thread(Func_Thread, &data);
109 al_start_thread(thread_1);
110
111 al_lock_mutex(data.mutex);
112 while (!data.ready){
113
114 al_wait_cond(data.cond, data.mutex);
115
116 }
117 al_unlock_mutex(data.mutex);
118
119 al_lock_mutex(data.mutex);
120 data.modi_X = true;
121 data.ready = false;
122 al_unlock_mutex(data.mutex);
123
124 thread_2 = al_create_thread(Func_Thread, &data);
125 al_start_thread(thread_2);
126
127 al_lock_mutex(data.mutex);
128 while (!data.ready){
129
130 al_wait_cond(data.cond, data.mutex);
131
132 }
133 al_unlock_mutex(data.mutex);
134
135
136 while(1)
137 {
138 ALLEGRO_EVENT ev;
139 al_wait_for_event(event_queue, &ev);
140
141 if(ev.type == ALLEGRO_EVENT_TIMER) {
142 redraw = true;
143 }
144 else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
145 break;
146 }
147 else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
148 break;
149 }
150 if(redraw && al_is_event_queue_empty(event_queue)) {
151 redraw = false;
152
153 al_lock_mutex(data.mutex);
154 al_draw_bitmap(bouncer, data.posiX, data.posiY, 0);
155 al_unlock_mutex(data.mutex);
156
157 al_flip_display();
158 }
159 }
160 al_destroy_thread(thread_1);
161 al_destroy_thread(thread_2);
162
163 al_destroy_bitmap(bouncer);
164 al_destroy_timer(timer);
165 al_destroy_display(display);
166 al_destroy_event_queue(event_queue);
167
168 return 0;
169}
170
171 static void *Func_Thread(ALLEGRO_THREAD *thr, void *arg){
172
173 DATA *data = (DATA*) arg;
174 float num = 0.1;
175
176 al_lock_mutex(data->mutex);
177
178 bool modi_X = data->modi_X;
179 data->ready = true;
180 al_broadcast_cond(data->cond);
181
182 al_unlock_mutex(data->mutex);
183
184 while(!al_get_thread_should_stop(thr)){
185
186 al_lock_mutex(data->mutex);
187 if(modi_X)
188 data->posiX += num;
189 else
190 data->posiY += num;
191 al_unlock_mutex(data->mutex);
192
193 al_rest(0.01);
194
195 }
196
197
198 return NULL;
199 }
I would like to delete the <stdio.h> include and add the native dialogs addon but I think that would complicate a bit more things for a newbie.
|
weapon_S
Member #7,859
October 2006
|
al_wait_cond is weird, but I get it. Except for: The Manual said: al_wait_cond can return for other reasons than the condition becoming true (e.g. the process was signalled). Somebody wants to explain that to me, please? |
Neil Walker
Member #210
April 2000
|
it was told to by the system. Neil. wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie |
weapon_S
Member #7,859
October 2006
|
Ha, I get it now |
Matthew Leverton
Supreme Loser
January 1999
|
When drawing the bitmap, you could do something like: float x, y; al_lock_mutex(data.mutex); x = data.posiX; y = data.posiY; al_unlock_mutex(data.mutex); al_draw_bitmap(bouncer, x, y, 0); It won't hold the mutex lock as long, and generally that's a good thing. |
AMCerasoli
Member #11,955
May 2010
|
I guess it's a good way to show the importance of blocking and unblocking the mutex the less possible. But it's really necessary do something like that in a real game?. Because that would imply creating a whole system to avoid having dispersed variables all over the code.
|
Matthew Leverton
Supreme Loser
January 1999
|
The entire example is contrived, so it really doesn't matter. |
|
1
2
|