|
This thread is locked; no one can reply to it. |
1
2
|
The Community Needs You. New Tutorial (Threads) |
AMCerasoli
Member #11,955
May 2010
|
A crazy noob has just created a new but uncompleted tutorial and put it on the Wiki, it's your objective to clean it and refine it. So others members can use it and not get confused. Objectives: - Orthography - Typos - Expressions
START Published by: UBISOFT™ A game by: AMCerasoli™
|
weapon_S
Member #7,859
October 2006
|
You don't explain well why you should check for the is_ready flag, you skip explaining lock_cond, there were some typo's and I still can't log into the wiki[1]. |
AMCerasoli
Member #11,955
May 2010
|
When the Wiki read your sign, said NO WAY BODY!
|
gnolam
Member #2,030
March 2002
|
-- |
AMCerasoli
Member #11,955
May 2010
|
Oh, thanks gnolam, I didn't know anything about initialization list, well I think was obvious hohohoho. Anyway I have changed it: 1
2class DATA{
3
4 public:
5
6 ALLEGRO_MUTEX *mutex;
7 ALLEGRO_COND *cond;
8 float posiX;
9 float posiY;
10 bool modi_X;
11 bool ready;
12
13 DATA() : mutex(al_create_mutex()),
14 cond(al_create_cond()),
15 posiX (0),
16 posiY (0),
17 modi_X(false),
18 ready (false) {}
19
20 ~DATA(){
21
22 al_destroy_mutex(mutex);
23 al_destroy_cond(cond);
24
25 }
26
27};
I think now it's fine. and what for it's the {} at the end now? @weapon_S I can't manage to explain better the example, how would you explain it? write it here, and I'll post it. Only that part that you said. {"name":"604195","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/9\/99e8f31cf663c1df6d02aa0e3ba52274.png","w":343,"h":623,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/9\/99e8f31cf663c1df6d02aa0e3ba52274"}
|
Timorg
Member #2,028
March 2002
|
In that loose {}, you should be checking the return values of al_create_mutex() and al_create_cond(), if they failed to be created, then either throwing an exception, or set a value to mark the class as bad. ____________________________________________________________________________________________ |
Thomas Fjellstrom
Member #476
June 2000
|
Or have a separate init method that can return a failure. -- |
weapon_S
Member #7,859
October 2006
|
Some things I don't understand, some things I think should be improved, but don't know how, and some things I know are wrong but-what-the-hey are marked with triple question marks \??? 1'''Under Construction'''
2
3In this section we'll learn how to use the Allegro 5 threading interface.
4=== Abstract ===
5
6In this example we're going to use the same bitmap created in the previous example, but instead of changing its axis with the mouse, we're going to let two thread to modified them.
7
8<source lang="c">
9#include <stdio.h>
10#include <allegro5/allegro.h>
11
12class DATA{
13
14 public:
15
16 ALLEGRO_MUTEX *mutex;
17 ALLEGRO_COND *cond;
18 float posiX;
19 float posiY;
20 bool modi_X;
21 bool ready;
22
23 DATA() : mutex(al_create_mutex()),
24 cond(al_create_cond()),
25 posiX (0),
26 posiY (0),
27 modi_X(false),
28 ready (false) {}
29
30 ~DATA(){
31
32 al_destroy_mutex(mutex);
33 al_destroy_cond(cond);
34
35 }
36
37};
38
39const float FPS = 30;
40const int SCREEN_W = 640;
41const int SCREEN_H = 480;
42const int BOUNCER_SIZE = 32;
43
44static void *Func_Thread(ALLEGRO_THREAD *thr, void *arg);
45
46int main(int argc, char **argv)
47{
48 ALLEGRO_DISPLAY *display = NULL;
49 ALLEGRO_EVENT_QUEUE *event_queue = NULL;
50 ALLEGRO_TIMER *timer = NULL;
51 ALLEGRO_BITMAP *bouncer = NULL;
52 ALLEGRO_THREAD *thread_1 = NULL;
53 ALLEGRO_THREAD *thread_2 = NULL;
54
55 bool redraw = true;
56
57 if(!al_init()) {
58 fprintf(stderr, "failed to initialize allegro!\n");
59 return -1;
60 }
61
62 if(!al_install_mouse()) {
63 fprintf(stderr, "failed to initialize the mouse!\n");
64 return -1;
65 }
66
67 timer = al_create_timer(1.0 / FPS);
68 if(!timer) {
69 fprintf(stderr, "failed to create timer!\n");
70 return -1;
71 }
72
73 display = al_create_display(SCREEN_W, SCREEN_H);
74 if(!display) {
75 fprintf(stderr, "failed to create display!\n");
76 al_destroy_timer(timer);
77 return -1;
78 }
79
80 bouncer = al_create_bitmap(BOUNCER_SIZE, BOUNCER_SIZE);
81 if(!bouncer) {
82 fprintf(stderr, "failed to create bouncer bitmap!\n");
83 al_destroy_display(display);
84 al_destroy_timer(timer);
85 return -1;
86 }
87
88 al_set_target_bitmap(bouncer);
89 al_clear_to_color(al_map_rgb(255, 0, 255));
90 al_set_target_bitmap(al_get_backbuffer(display));
91 event_queue = al_create_event_queue();
92
93 if(!event_queue) {
94 fprintf(stderr, "failed to create event_queue!\n");
95 al_destroy_bitmap(bouncer);
96 al_destroy_display(display);
97 al_destroy_timer(timer);
98 return -1;
99 }
100
101 al_register_event_source(event_queue, al_get_display_event_source(display));
102 al_register_event_source(event_queue, al_get_timer_event_source(timer));
103 al_register_event_source(event_queue, al_get_mouse_event_source());
104 al_clear_to_color(al_map_rgb(0,0,0));
105 al_flip_display();
106 al_start_timer(timer);
107
108 DATA data;
109
110 thread_1 = al_create_thread(Func_Thread, &data);
111 al_start_thread(thread_1);
112
113 al_lock_mutex(data.mutex);
114 while (!data.ready){
115
116 al_wait_cond(data.cond, data.mutex);
117
118 }
119 al_unlock_mutex(data.mutex);
120
121 al_lock_mutex(data.mutex);
122 data.modi_X = true;
123 data.ready = false;
124 al_unlock_mutex(data.mutex);
125
126 thread_2 = al_create_thread(Func_Thread, &data);
127 al_start_thread(thread_2);
128
129 al_lock_mutex(data.mutex);
130 while (!data.ready){
131
132 al_wait_cond(data.cond, data.mutex);
133
134 }
135 al_unlock_mutex(data.mutex);
136
137
138 while(1)
139 {
140 ALLEGRO_EVENT ev;
141 al_wait_for_event(event_queue, &ev);
142
143 if(ev.type == ALLEGRO_EVENT_TIMER) {
144 redraw = true;
145 }
146 else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
147 break;
148 }
149 else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
150 break;
151 }
152 if(redraw && al_is_event_queue_empty(event_queue)) {
153 redraw = false;
154
155 al_lock_mutex(data.mutex);
156 data.modi_X = true;
157 data.ready = false;
158 al_unlock_mutex(data.mutex);
159
160 al_draw_bitmap(bouncer, data.posiX, data.posiY, 0);
161
162
163 al_flip_display();
164 }
165 }
166 al_destroy_thread(thread_1);
167 al_destroy_thread(thread_2);
168
169 al_destroy_bitmap(bouncer);
170 al_destroy_timer(timer);
171 al_destroy_display(display);
172 al_destroy_event_queue(event_queue);
173
174 return 0;
175}
176
177 static void *Func_Thread(ALLEGRO_THREAD *thr, void *arg){
178
179 DATA *data = (DATA*) arg;
180 float num = 0.1;
181
182 al_lock_mutex(data->mutex);
183
184 bool modi_X = data->modi_X;
185 data->ready = true;
186 al_broadcast_cond(data->cond);
187
188 al_unlock_mutex(data->mutex);
189
190 while(!al_get_thread_should_stop(thr)){
191
192 al_lock_mutex(data->mutex);
193 if(modi_X)
194 data->posiX += num;
195 else
196 data->posiY += num;
197 al_unlock_mutex(data->mutex);
198
199 al_rest(0.01);
200
201 }
202
203
204 return NULL;
205 }
206</source>
207
208=== Let's get started ===
209
210
211<source lang="c">
212class DATA{
213
214 public:
215
216 ALLEGRO_MUTEX *mutex;
217 ALLEGRO_COND *cond;
218 float posiX;
219 float posiY;
220 bool modi_X;
221 bool ready;
222
223 DATA() : mutex(al_create_mutex()),
224 cond(al_create_cond()),
225 posiX (0),
226 posiY (0),
227 modi_X(false),
228 ready (false) {}
229
230 ~DATA(){
231
232 al_destroy_mutex(mutex);
233 al_destroy_cond(cond);
234
235 }
236
237};
238</source>
239
240First we create a class, which is going to contain the data we want to exchange between threads.
241
242<source lang="c">ALLEGRO_MUTEX *mutex</source>
243
244Here we declare a /mutex/ (mutual exclusion). In essence it's a flag that's supposed to tell other threads to leave some data alone. You can't set it directly, though. This should become clear why.
245
246<source lang="c">ALLEGRO_COND *cond;</source>
247
248Here we declare a /condition/. It is sort of a sign that can asynchrously be picked up by other threads. Again you'll have to use functions to use it.
249
250<source lang="c">
251 float posiX;
252 float posiY;
253 bool modi_X;
254 bool ready;</source>
255
256<code>posiX</code>, and <code>posiY</code> are the X, and Y coordinates of our bitmap, <code>modi_X</code> and <code>ready</code> are two flags that we're going to use later on.
257
258<source lang="c">
259
260 DATA() : mutex(al_create_mutex()),
261 cond(al_create_cond()),
262 posiX (0),
263 posiY (0),
264 modi_X(false),
265 ready (false) {}
266
267 ~DATA(){
268
269 al_destroy_mutex(mutex);
270 al_destroy_cond(cond);
271
272 }
273
274</source>
275
276Class's constructor, using a initialization list. Followed by the destructor. '''Note:''' you cannot make an instance of this object on global scope, because <code>al_create_mutex</code> and <code>al_create_cond</code> would be called before <code>al_init</code>.
277
278<source lang="c"> ALLEGRO_THREAD *thread_1 = NULL;
279 ALLEGRO_THREAD *thread_2 = NULL; </source>
280
281A /thread/ is like a program running _separately_. Separately means you have no idea how far it has run, and neither do they know about eachothers globals???.
282
283<source lang="c">
284
285 DATA data;
286
287 thread_1 = al_create_thread(Func_Thread, &data);
288</source>
289<code>data</code> is neatly created after <code>al_init</code>. <code>thread_1</code> is allocated. Don't forget to deallocate it afterwards.
290???Shouldn't you check it's value? The thread will be running the function <code>Func_thread</code> and getting the pointer <code>*data</code> as its argument when it starts. ???(Or only after it started it head hurts) Because this thread holds all the control information of <code>thread_1</code>, this thread is called the /parent/ thread and <code>thread_1</code> is called a /child/ thread.
291<source lang="c">
292 al_start_thread(thread_1);
293</source>
294Now, after god knows how much time Func_Thread will be called god knows how fast, under the nominator of <code>thread_1</code>.
295Next lines get technical, but can be seen as 1 unit:
296<source lang="c">
297 al_lock_mutex(data.mutex);
298 while (!data.ready){
299
300 al_wait_cond(data.cond, data.mutex);
301
302 }
303 al_unlock_mutex(data.mutex);
304<\source>
305Firstly, we /lock/ a /mutex/. An analogy would be shouting "it's my turn now!". If this thread is the first one to shout, it gets the mutex. If an other thread /locked/ the /mutex/ first, this thread will have to wait until that particular thread /unlocks/ it.
306<code>al_wait_cond</code> takes a /locked mutex/ as an argument??? and then unlocks it. Meanwhile it pauses this thread until the /condition/ is /signaled/. There are two reasons you can't use this /condition/ directly to signal something has happened. Number one is: multiple threads could have been waiting for the same condition and have responded to that condition, before you get the chance to do anything.??? Number two is: the thread can also continue whenever the OS feels like kicking it.
307Now you should understand the reason a <code>while</code> loop was put around <code>al_wait_cond</code>; and a variable named <code>ready</code> was put into the <code>data</code> structure.
308<source lang="c">
309 al_lock_mutex(data.mutex);
310 data.modi_X = true; //???Don't you actually want to run these lines before the previous al_unlock_mutex
311 data.ready = false; //???Don't you actually want to run these lines before the previous al_unlock_mutex
312 al_unlock_mutex(data.mutex);
313
314 thread_2 = al_create_thread(Func_Thread, &data);
315 al_start_thread(thread_2);
316
317 al_lock_mutex(data.mutex);
318 while (!data.ready){
319
320 al_wait_cond(data.cond, data.mutex);
321
322 }
323 al_unlock_mutex(data.mutex);
324
325</source>
326
327Everything until here should be already clear.
328
329# ??? In what order are you discussing the file? In what order was I discussing the file? I already discussed this???
330<source lang="c">DATA data;</source>
331
332Very obvious, we create our object '''after''' initializing allegro since it's using some allegro functions.
333
334<source lang="c">thread_1 = al_create_thread(Func_Thread, &data);
335al_start_thread(thread_1);</source>
336
337Here we create our thread and immediately the data is sent. <code>Func_Thread</code> it's a pointer to a function and <code>&data</code> it's the address of our recently created object. And since when a thread is created, it is initially in a suspended state, we need to call <code>al_start_thread(thread_1)</code> to call its actual execution.
338
339So, you write your own function that matches this prototype:
340
341<source lang="c"> static void *Func_Thread(ALLEGRO_THREAD *thr, void *arg) </source>
342
343Whatever you do inside this functions it's going to be running on a different thread.
344
345<source lang="c">
346
347static void *Func_Thread(ALLEGRO_THREAD *thr, void *arg){
348
349 DATA *data = (DATA*) arg;
350 float num = 0.1;
351
352 al_lock_mutex(data->mutex);
353
354 bool modi_X = data->modi_X;
355 data->ready = true;
356 al_broadcast_cond(data->cond);
357
358 al_unlock_mutex(data->mutex);
359
360 while(!al_get_thread_should_stop(thr)){
361
362 al_lock_mutex(data->mutex);
363 if(modi_X)
364 data->posiX += num;
365 else
366 data->posiY += num;
367 al_unlock_mutex(data->mutex);
368
369 al_rest(0.01);
370
371 }
372
373
374 return NULL;
375 }
376</source>
377
378The data you sent using <code>al_create_thread()</code> it's received by this function as a void pointer data type <code>(void *arg)</code>. So the first thing we need to do here inside, is convert our object back to a DATA data type, which is our original class.
379
380<source lang="c"> DATA *data = (DATA*) arg; </source>
381
382With some typecasting it's done. Remember that data now it's a pointer to a DATA object so we'll use <code>data->example</code> instead of <code>data.example</code>.
383
384<source lang="c"> float num = 0.1; </source>
385
386This is the value we're going to add to our X or Y axis.
387
388<source lang="c"> al_lock_mutex(data->mutex); </source>
389
390And WTH is this?, well, this is how we tell allegro that one of our many threads it's going to use a shared resource. Our data object is also available to our main thread, and it will be available to two more threads. Remember: whichever thread shouts: "My turn!" first, should get sole access to this sort of shared data... for as long as its turn lasts.
391
392So for that reason each time we use our data in each thread we need to lock it first. And when we're done we can unlock it.
393
394<source lang="c"> bool modi_X = data->modi_X;
395 data->ready = true;
396 al_broadcast_cond(data->cond); </source>
397
398So, here we're creating a bool variable , and assign it a value, as you can see when we created our DATA object this value is initialized as false, so the <code>bool modi_X</code> variable of this thread the first time it is run, is going to be false. We're doing this because we need to tell the parent thread to modified the X value and the other to modified the Y value, so the thread which receive <code>modi_X</code> (Modify X) as true, is going to do exactly that, modified the X Axi, and the thread which receive <code>modi_X</code> as false, is going to modified the Y axis.
399
400And since this is the first thread ???true but actually not very generic case:(we haven't create/started the second thread) it's going to recive the <code>modi_X</code> value as false.
401
402<source lang="c"> data->ready = true; </source>
403
404This is the second flag of our data object, we need to use this, because our parent thread needs to wait until we have assigned the <code>modi_X</code> value. Since we're working with threads we can never assume the order or speed in which two things in parallel happen. So this flag along with the cond struct, allow us to tell our parent thread, when it can move on.
405
406
407
408<source lang="c">al_lock_mutex(data.mutex);
409 if (!data.ready)
410 al_wait_cond(data.cond, data.mutex);
411
412 al_unlock_mutex(data.mutex)
413 </source>
414
415This is what we have in our parent thread, basically if data.ready isn't true that means that the second tread haven't initialized the modi_X variable, so we need to wait. and how do we know when the second thread it's done?, how much do we need to wait? here is where conditions come in.
416
417<source lang="c">al_wait_cond(data.cond, data.mutex);</source>
418
419<code>al_wait_cond</code> it's waiting until a signal, a broadcast signal it's sent, and as you can see:
420
421<source lang="c"> al_broadcast_cond(data->cond) </source>
422
423Our thread function (<code>Func_Thread()</code>) 6th line does exactly that.
424
425So if for some reason our parent thread arrives to:
426
427<source lang="c">while (!data.ready){</source>
428
429and ready isn't true, that means we need to wait, so we enter to the loop, and immediately <code>al_wait_cond(data.cond, data.mutex)</code> is called.
430
431On the other hand if when the parent thread arrives to:
432
433<source lang="c">while (!data.ready){</source>
434
435and ready is true, that means that we can move on, so we're not going to wait for any condition.
436
437<source lang="c">al_broadcast_cond(data->cond); </source>
438
439So for that reason, after assign the threads modi_X to false, we change the ready flag to true, to tell to the parent thread that he doesn't need to wait, because the first thread it's ready, but in case he is waiting, we also broadcast our condition so he can move on with this line.
440
441<source lang="c"> al_unlock_mutex(data->mutex); </source>
442
443Finally we unlock our mutex to tell Allegro that we're not going to be using the data object anymore so other threads can start using it.
444
445Ok, we need to go back to our parent thread, and make a little review:
446
447
448
449<source lang="c" line start=0>
450 thread_1 = al_create_thread(Func_Thread, &data);
451 al_start_thread(thread_1);
452
453 al_lock_mutex(data.mutex);
454 if (!data.ready)
455
456 al_wait_cond(data.cond, data.mutex);
457
458 al_unlock_mutex(data.mutex);
459
460 al_lock_mutex(data.mutex);
461 data.modi_X = true;
462 data.ready = false;
463 al_unlock_mutex(data.mutex);
464
465 thread_2 = al_create_thread(Func_Thread, &data);
466 al_start_thread(thread_2);
467
468 al_lock_mutex(data.mutex);
469 if (!data.ready)
470
471 al_wait_cond(data.cond, data.mutex);
472
473 al_unlock_mutex(data.mutex);
474
475</source>
476
477=== Quick Review ===
478
479* In line 1 we create the thread.
480* In line 2 we start the thread.
481* in line 4 we lock our mutex because we're going to check if <code>ready</code> it's true
482* In case it's true that means our second tread for some reason haven't initialized its <code>mosi_X</code> bool variable, so we need to wait.
483* In line 6 we start waiting.
484* Ok our second thread has broadcast the conditional that means he is ready.
485* In line 8 we unlock the mutex because we're not going to use it anymore.
486* In line 10 we lock the mutex again, we need to change our variables because we're about to create another thread, and if we don't change the flags the second thread would be a complete mess.
487* In line 11 we change our <code>modi_X</code> variable to true, that way our second thread it's going to modified the X value of our bitmap.
488* In line 12 we change back our ready variable to false again, because now we need to do the same with the second thread, we need to know when it's ready.
489* In line 13 we unlock everything again.
490
491And the next lines does everything again, but for the second thread.
492=== Two Threads Running===
493At this point we have two threads running!
494
495Now what?
496
497Well those threas are changing the posi_X and posi_Y variables, so if you don't hurry up and draw the bitmap you're not going to see anything.
498
499But before drawing anything let's see how these threads are changing these variables:
500
501<source lang="c">
502
503 while(!al_get_thread_should_stop(thr)){
504
505 al_lock_mutex(data->mutex);
506 if(modi_X)
507 data->posiX += num;
508 else
509 data->posiY += num;
510 al_unlock_mutex(data->mutex);
511
512 al_rest(0.01);
513
514 }
515
516
517 return NULL;
518
519 </source>
520
521We're back to our <code>Func_Thread()</code> function.
522
523After initializing some values and telling to our parent thread that we're ready, the thread enter in a loop. A very simple loop that you should understand very well. To keep it simple we're not going to create another timer but just use <code>al_rest()</code> which allow us to rest the thread some seconds, otherwise this loop would run so fast that we wouldn't be able to see our bitmap on the screen.
524
525<source lang="c">while(!al_get_thread_should_stop(thr)) </source>
526
527The same way this thread talked with the parent thread to tell it was ready, this function <code></code> allows the parent thread to talk with this thread, but this time we use it to tell our thread that must stop.
528
529As you can see each time we modified the data object in all threads we need to lock it and unlock it using <code>al_luck_mutex()</code> and <code>al_luck_mutex()</code> respectively.
530
531If <code>al_get_thread_should_stop(thr)</code> returns true, the thread will stop. <code>thr</code> it's the other value that <code>Func_Thread</code> receives. It's nothing more than a pointer to the current thread.
532
533So we're done with the thread function. Now let's advance in our parent thread.
534
535
536
537
538<source lang="c" line start="0"> while(1)
539 {
540 ALLEGRO_EVENT ev;
541 al_wait_for_event(event_queue, &ev);
542
543 if(ev.type == ALLEGRO_EVENT_TIMER) {
544 redraw = true;
545 }
546 else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
547 break;
548 }
549 else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
550 break;
551 }
552 if(redraw && al_is_event_queue_empty(event_queue)) {
553 redraw = false;
554
555 al_lock_mutex(data.mutex);
556 float X = data.posiX;
557 float Y = data.posiY;
558 al_unlock_mutex(data.mutex);
559
560 al_draw_bitmap(bouncer, X, Y, 0);
561
562 al_flip_display();
563 }
564 }
565 al_destroy_thread(thread_1);
566 al_destroy_thread(thread_2);
567
568 al_destroy_bitmap(bouncer);
569 al_destroy_timer(timer);
570 al_destroy_display(display);
571 al_destroy_event_queue(event_queue);
572
573</source>
574
575This shouldn't be nothing new. As you can see in line 17, 18, 19 and 20, we are creating two variables and initializing them with the corresponding value, this is to clarify, that you should keep locked the mutex of determined object the less posible.
576
577<source lang="c"> al_destroy_thread(thread_1);
578 al_destroy_thread(thread_2) </source>
579
580And finally we're destroying the threads when we exit the program. This implicitly performs <code>al_join_thread</code> which at the same time implicitly calls <code>al_set_thread_should_stop</code> first, so the while that is running in our threads are going to stop.
581
582The End.
|
Neil Walker
Member #210
April 2000
|
Didn't I read somewhere or other today about the evils that beset video bitmaps and threads? Neil. wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie |
CosmicR
Member #6,889
February 2006
|
It should be in C, since Allegro is a C library.
|
Thomas Fjellstrom
Member #476
June 2000
|
Neil Walker said: Didn't I read somewhere or other today about the evils that beset video bitmaps and threads? You shouldn't touch a GL/DX context from more than one thread at a time. Bad things can, and WILL happen. -- |
weapon_S
Member #7,859
October 2006
|
Somebody willing to post my blerp of text to the wiki and maybe give it a critical look? |
AMCerasoli
Member #11,955
May 2010
|
I'll update the tut when I get the time. all this thing about threads it's incredible. Edit: Why are you using those // and _ _ like if you were writting on allegro.cc? On the Wiki that doesn't work. ok we have some questions: 1 - A thread is like a program running separately. Separately means you have no idea how far it has run, and neither do they know about each others globals?. 2 -thread_1 is allocated. Don't forget to deallocate it afterwards. Shouldn't you check Neither al_start_thread and al_create_thread returns a value so how could I check it? 3 - The thread will be running the function Func_thread and getting the pointer *data as its argument when it starts. (Or only after it started it head hurts) To be honest I don't understand the question. 4 - al_wait_cond takes a locked mutex as an argument??? On entering this function, mutex must be locked by the calling thread. The function will atomically release mutex and block on cond. That is what the manual says, I don't know if you was referring to another thing. 5 - In what order are you discussing the file? In what order was I discussing the file? I already discussed this??? When I said "Everything until here should be already clear" I was referring to the rest of the code the initialization of allegro, mouse etc, I guess I can remove it, though. Here: al_lock_mutex(data.mutex); while (!data.ready){ al_wait_cond(data.cond, data.mutex); } al_unlock_mutex(data.mutex); Instead of a while can't we use an if? PS: the <code></code> tags shows the letters too small, can't be increased?
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
AMCerasoli said: Neither al_start_thread and al_create_thread returns a value so how could I check it? Read al_create_thread again - it returns an ALLEGRO_THREAD*, 0 on failure. AMCerasoli said: Instead of a while can't we use an if? No, because al_wait_cond may return for reasons other than the condition becoming true. That's why you need to keep checking the variable. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
weapon_S
Member #7,859
October 2006
|
I thought // , ** and __ were called "wiki-markup"
|
Thomas Fjellstrom
Member #476
June 2000
|
weapon_S said: Woops, my bad. I was confused for a second. It is a very bad idea to use globals to communicate between threads, it is however not impossible. You can pass in an argument to al_create_thread just like you can with pthreads. -- |
AMCerasoli
Member #11,955
May 2010
|
I read somewhere that threads shouldn't be called "parents" or "child" I can't remember where, though. In the tutorial we're using those terms, should I keep it?. Edit: I have another question... why is useful a cond? if for example I have al_lock_mutex(data.mutex); while(!data.ready){} al_unlock_mutex(data.mutex); and that's it? that would wait until ready is... ready.
|
weapon_S
Member #7,859
October 2006
|
That would wait forever. (Variable is locked.) |
Matthew Leverton
Supreme Loser
January 1999
|
AMCerasoli said: I have another question... why is useful a cond? if for example I have It would never release the mutex. It would sit in there forever blocking the other threads that want the mutex in order to change the variable. When you wait on a condition variable, it essentially goes like:
|
weapon_S
Member #7,859
October 2006
|
I had to think for a sec before I saw that was correct. Slightly more elaborate steps written out. (You call this a 'diagram'? )
|
AMCerasoli
Member #11,955
May 2010
|
Ohhhh it's true... , know I think I understand it very well... al_wait_cond() unlock the mutex and block on the cond (the same that the manua says, I couldn't understand it the first time I read it ). I'm thinking in many threads using the same data, it's a good idea having just one cond and many flag to check if all the threads have done their job? something like: al_lock_mutex(data.mutex); while(!data.flag1 || !data.flag2 || !data.flag3){ al_wait_cond(cond, mutex); } al_unlock_mutex(data.mutex); I don't need more conds right? Edit: I have another question... What is the point of having multiple threads if I can't use them to load bitmaps, fonts since they're loaded as memory bitmaps? I guess I have no problem by loading sound on another thread right?
|
Thomas Fjellstrom
Member #476
June 2000
|
The a wait condition also doesn't spin in a loop using 100% cpu. Where as a simple loop would. One condition var should be fine so long as the stuff you're waiting for properly sets all flags (or you'll never fully wake up). -- |
AMCerasoli
Member #11,955
May 2010
|
I have another question: If the object that I sent to the thread has a function, when I call the function from the main thread do I need to lock the mutex too? data.cout_this("Hello Thread"); Yes it's possible, if someone wants more info read this: http://www.thinkingparallel.com/2006/10/15/a-short-guide-to-mastering-thread-safety/ BTW I didn't know that rand() wasn't thread-safe...
|
BAF
Member #2,981
December 2002
|
You need to lock the mutex no matter what (unless you know you've already locked it earlier, otherwise you'll deadlock) for critical sections. |
AMCerasoli
Member #11,955
May 2010
|
Yhea it's done... Someone has some ideas to create another simple one? I thought in one which multiple threads load a lot of images and make the comparison between using or not threads... But I don't want to load all those images to the wiki, I was thinking if there would be another idea like that, which shows the difference between multi-thread and just one thread very clear.
|
|
1
2
|