|
adding Multithreading pthread.h |
CIRCLE
Member #5,301
December 2004
|
I have been messing around for some time with a small game and now trying to add multithreading to the equation. Sure it is not needed but I just wanted to test it out this is what I got. Problem lies with in where at game start if just freezes my computer and I have to hit the reset button. I am unsure to what I am missing or making my mistake on, but right at program start it tries to do the multithreading area of the program which it shouldn't. Even removing the calls doesn't stop it from running. skipping most of the non needed stuff Full program link can be added if needed 1#include <pthread.h>
2pthread_mutex_t threadsafe = PTHREAD_MUTEX_INITIALIZER;
3for (a = 1; a < maxa; a++){
4 xi[a] = rand() % 5 + 1;
5 yi[a] = rand() % 5 + 1;
6 x[a] = rand() % 500 + 20;
7 y[a] = rand() %400 + 20;
8 c[a] = makecol(rand() % 253 + 1, rand() % 253 + 1, rand() % 253 + 1);
9 }
10void* thread0(void* data)
11{
12 int my_thread_id = *((int*)data);
13 //For Pixelate Demo Addition
14 while(lives > 0)
15 {
16 if (pthread_mutex_lock(&threadsafe))
17 textprintf_ex(screen,font,SCREEN_W/2 - (4*19),SCREEN_H/2,makecol(255,255,255),-1,"Error: Thread mutex was locked");
18 for (a = 1; a < 100; a++){
19 if (x[a] > SCREEN_W - 4 - xi[a] || x[a] < 3 - xi[a])
20 xi[a] = -xi[a];
21 if (y[a] > Floors.y - 4 - yi[a] || y[a] < 13 - yi[a])
22 yi[a] = -yi[a];
23 x[a] = x[a] + xi[a];
24 y[a] = y[a] + yi[a];
25 //putpixel(active_page,x[a],y[a],c[a]);
26 circlefill(active_page,x[a],y[a],BallSize / 5,c[a]);
27 //putpixel(active_page,x[a] - xi[a],y[a] - yi[a],makecol(0,0,0));
28 }
29 if (pthread_mutex_unlock(&threadsafe))
30 textprintf_ex(screen,font,SCREEN_W/2 - (4*19),SCREEN_H/2,makecol(255,255,255),-1,"Error: Thread mutex was unlocked");
31 //For Pixelate demo addition
32 }
33 pthread_exit(NULL);
34 return NULL;
35}
36int id;
37 pthread_t pthread0;
38 int threadid0 = 0;
39 id = pthread_create(&pthread0, NULL, thread0, (void*)&threadid0);
40while(!key[KEY_ESC] && lives > 0)
41 {
42 pthread_mutex_lock(&threadsafe);
43 multicheck();
44 singlecheck();
45 movemouse();
46 mousehold();
47 drawback();
48 checkdead();
49
50
51 show_video_bitmap(active_page);
52 if (active_page == buffer)
53 active_page = buffer2;
54 else
55 active_page = buffer;
56 clear_to_color(active_page, makecol(0, 0, 0));
57 pthread_mutex_unlock(&threadsafe);
58 rest(1);
59
60 }
61pthread_mutex_destroy(&threadsafe);
62 //destroy_bitmap(active_page);
63
64
65 allegro_exit();
66 return;
67
68}
69END_OF_MAIN()
Most of the multithreading was taken directly from a book I was reading a while back. Game Programming All In One pg 405-413 for those who have the book. 1
2#include <pthread.h>
3#include "allegro.h"
4
5#define MODE GFX_AUTODETECT_FULLSCREEN
6#define WIDTH 640
7#define HEIGHT 480
8#define BLACK makecol(0,0,0)
9#define WHITE makecol(255,255,255)
10
11//define the sprite structure
12typedef struct SPRITE
13{
14 int dir, alive;
15 int x,y;
16 int width,height;
17 int xspeed,yspeed;
18 int xdelay,ydelay;
19 int xcount,ycount;
20 int curframe,maxframe,animdir;
21 int framecount,framedelay;
22}SPRITE;
23
24//variables
25BITMAP *buffer;
26BITMAP *ballimg[32];
27SPRITE theballs[2];
28SPRITE *balls[2];
29int done;
30int n;
31
32//create a new thread mutex to protect variables
33pthread_mutex_t threadsafe = PTHREAD_MUTEX_INITIALIZER;
34
35
36void erasesprite(BITMAP *dest, SPRITE *spr)
37{
38 //erase the sprite
39 rectfill(dest, spr->x, spr->y, spr->x + spr->width,
40 spr->y + spr->height, BLACK);
41}
42
43void updatesprite(SPRITE *spr)
44{
45 //update x position
46 if (++spr->xcount > spr->xdelay)
47 {
48 spr->xcount = 0;
49 spr->x += spr->xspeed;
50 }
51
52 //update y position
53 if (++spr->ycount > spr->ydelay)
54 {
55 spr->ycount = 0;
56 spr->y += spr->yspeed;
57 }
58
59 //update frame based on animdir
60 if (++spr->framecount > spr->framedelay)
61 {
62 spr->framecount = 0;
63 if (spr->animdir == -1)
64 {
65 if (--spr->curframe < 0)
66 spr->curframe = spr->maxframe;
67 }
68 else if (spr->animdir == 1)
69 {
70 if (++spr->curframe > spr->maxframe)
71 spr->curframe = 0;
72 }
73 }
74}
75
76//this version doesn't change speed, just direction
77void bouncesprite(SPRITE *spr)
78{
79 //simple screen bouncing behavior
80 if (spr->x < 0)
81 {
82 spr->x = 0;
83 spr->xspeed = -spr->xspeed;
84 spr->animdir *= -1;
85 }
86
87 else if (spr->x > SCREEN_W - spr->width)
88 {
89 spr->x = SCREEN_W - spr->width;
90 spr->xspeed = -spr->xspeed;
91 spr->animdir *= -1;
92 }
93
94 if (spr->y < 0)
95 {
96 spr->y = 0;
97 spr->yspeed = -spr->yspeed;
98 spr->animdir *= -1;
99 }
100
101 else if (spr->y > SCREEN_H - spr->height)
102 {
103 spr->y = SCREEN_H - spr->height;
104 spr->yspeed = -spr->yspeed;
105 spr->animdir *= -1;
106 }
107}
108
109BITMAP *grabframe(BITMAP *source,
110 int width, int height,
111 int startx, int starty,
112 int columns, int frame)
113{
114 BITMAP *temp = create_bitmap(width,height);
115 int x = startx + (frame % columns) * width;
116 int y = starty + (frame / columns) * height;
117 blit(source,temp,x,y,0,0,width,height);
118 return temp;
119}
120
121void loadsprites()
122{
123 BITMAP *temp;
124
125 //load sprite images
126 temp = load_bitmap("sphere.bmp", NULL);
127 for (n=0; n<32; n++)
128 ballimg[n] = grabframe(temp,64,64,0,0,8,n);
129 destroy_bitmap(temp);
130
131 //initialize the sprite
132 for (n=0; n<2; n++)
133 {
134 balls[n] = &theballs[n];
135 balls[n]->x = rand() % (SCREEN_W - ballimg[0]->w);
136 balls[n]->y = rand() % (SCREEN_H - ballimg[0]->h);
137 balls[n]->width = ballimg[0]->w;
138 balls[n]->height = ballimg[0]->h;
139 balls[n]->xdelay = 0;
140 balls[n]->ydelay = 0;
141 balls[n]->xcount = 0;
142 balls[n]->ycount = 0;
143 balls[n]->xspeed = 5;
144 balls[n]->yspeed = 5;
145 balls[n]->curframe = rand() % 32;
146 balls[n]->maxframe = 31;
147 balls[n]->framecount = 0;
148 balls[n]->framedelay = 0;
149 balls[n]->animdir = 1;
150 }
151}
152
153//this thread updates sprite 0
154void* thread0(void* data)
155{
156 //get this thread id
157 int my_thread_id = *((int*)data);
158
159 //thread's main loop
160 while(!done)
161 {
162 //lock the mutex to protect variables
163 if (pthread_mutex_lock(&threadsafe))
164 textout(buffer,font,"ERROR: thread mutex was locked",0,0,WHITE);
165
166 //erase sprite 0
167 erasesprite(buffer, balls[0]);
168
169 //update sprite 0
170 updatesprite(balls[0]);
171
172 //bounce sprite 0
173 bouncesprite(balls[0]);
174
175 //draw sprite 0
176 draw_sprite(buffer, ballimg[balls[0]->curframe],
177 balls[0]->x, balls[0]->y);
178
179 //print sprite number
180 textout(buffer, font, "0", balls[0]->x, balls[0]->y,WHITE);
181
182 //display sprite position
183 textprintf(buffer,font,0,10,WHITE,"THREAD ID %d, SPRITE (%3d,%3d)",
184 my_thread_id, balls[0]->x, balls[0]->y);
185
186 //unlock the mutex
187 if (pthread_mutex_unlock(&threadsafe))
188 textout(buffer,font,"ERROR: thread mutex unlock error",0,0,WHITE);
189
190 //slow down (this thread only!)
191 rest(10);
192 }
193
194 // terminate the thread
195 pthread_exit(NULL);
196
197 return NULL;
198}
199
200//this thread updates sprite 1
201void* thread1(void* data)
202{
203 //get this thread id
204 int my_thread_id = *((int*)data);
205
206 //thread's main loop
207 while(!done)
208 {
209 //lock the mutex to protect variables
210 if (pthread_mutex_lock(&threadsafe))
211 textout(buffer,font,"ERROR: thread mutex was locked",0,0,WHITE);
212
213 //erase sprite 1
214 erasesprite(buffer, balls[1]);
215
216 //update sprite 1
217 updatesprite(balls[1]);
218
219 //bounce sprite 1
220 bouncesprite(balls[1]);
221
222 //draw sprite 1
223 draw_sprite(buffer, ballimg[balls[1]->curframe],
224 balls[1]->x, balls[1]->y);
225
226 //print sprite number
227 textout(buffer, font, "1", balls[1]->x, balls[1]->y,WHITE);
228
229 //display sprite position
230 textprintf(buffer,font,0,20,WHITE,"THREAD ID %d, SPRITE (%3d,%3d)",
231 my_thread_id, balls[1]->x, balls[1]->y);
232
233 //unlock the mutex
234 if (pthread_mutex_unlock(&threadsafe))
235 textout(buffer,font,"ERROR: thread mutex unlock error",0,0,WHITE);
236
237 //slow down (this thread only!)
238 rest(20);
239 }
240
241 // terminate the thread
242 pthread_exit(NULL);
243
244 return NULL;
245}
246
247//program's primary thread
248void main(void)
249{
250 int id;
251 pthread_t pthread0;
252 pthread_t pthread1;
253 int threadid0 = 0;
254 int threadid1 = 1;
255
256 //initialize
257 allegro_init();
258 set_color_depth(16);
259 set_gfx_mode(MODE, WIDTH, HEIGHT, 0, 0);
260 srand(time(NULL));
261 install_keyboard();
262 install_timer();
263
264 //create double buffer
265 buffer = create_bitmap(SCREEN_W,SCREEN_H);
266
267 //load ball sprite
268 loadsprites();
269
270 //create the thread for sprite 0
271 id = pthread_create(&pthread0, NULL, thread0, (void*)&threadid0);
272
273 //create the thread for sprite 1
274 id = pthread_create(&pthread1, NULL, thread1, (void*)&threadid1);
275
276 //main loop
277 while (!key[KEY_ESC])
278 {
279 //lock the mutex to protect double buffer
280 pthread_mutex_lock(&threadsafe);
281
282 //display title
283 textout(buffer, font, "MultiThread Program (ESC to quit)", 0, 0, WHITE);
284
285 //update the screen
286 acquire_screen();
287 blit(buffer,screen,0,0,0,0,SCREEN_W-1,SCREEN_H-1);
288 release_screen();
289
290 //unlock the mutex
291 pthread_mutex_unlock(&threadsafe);
292
293 //note there is no delay
294 }
295
296 //tell threads it's time to quit
297 done++;
298 rest(100);
299
300 //kill the mutex (thread protection)
301 pthread_mutex_destroy(&threadsafe);
302
303 //remove objects from memory
304 destroy_bitmap(buffer);
305
306 //delete sprites
307 for (n=0; n<32; n++)
308 destroy_bitmap(ballimg[n]);
309
310 return;
311}
312
313END_OF_MAIN()
-I edit a lot. Prepare thyself. |
CGamesPlay
Member #2,559
July 2002
|
Quote: Game Programming All In One pg 405-413 for those who have the book. We hear a ton of horrible programming practices gotten from this book. [edit] -- Ryan Patterson - <http://cgamesplay.com/> |
GullRaDriel
Member #3,861
September 2003
|
Nothing else to say than what CGamesPlay said. Too slow :p "Code is like shit - it only smells if it is not yours" |
CIRCLE
Member #5,301
December 2004
|
Fixed a few things. But still remains that right at start the multithreaded part of the program is trying to start and just freezes. I used a graphical feature to show what was being multithreaded. At the start of the game is a main menu the "bouncing balls" should be applied when the game is started but instead they are starting at the main screen it gets (guessing) 3-5 loops and locks up. What I do not understand is what am I doing that starts the calls for the multithreaded parts of my program. Compiles no errors just locks up on run. -I edit a lot. Prepare thyself. |
GullRaDriel
Member #3,861
September 2003
|
Yeah, you must have a dead lock somewhere in your code. That is typically why threaded program froze. "Code is like shit - it only smells if it is not yours" |
CIRCLE
Member #5,301
December 2004
|
What should I be looking for in my program. What kind of things might cause this. It really doesn't effect the game play to have it out now, but perhaps later when there is more going on I may want to have it implemented just in case. I code in a simple form "Newbish" so to speak.
Showing how simplistic I keep things. Maybe I should add everything that adds multithreading until I get the error. Let me see what causes it exactly. -I edit a lot. Prepare thyself. |
GullRaDriel
Member #3,861
September 2003
|
You should add some TRACE(...) in your code to see where you stop. Step by step debugging could help too. "Code is like shit - it only smells if it is not yours" |
CIRCLE
Member #5,301
December 2004
|
Trace is new to me should try it out. I am fairly new to the programming thing and havent done any debugging stuff with my compiler yet will have to try that aswell. hitting the post button to test ok with just this line commented out the program works. circlefill(active_page,x[a],y[a],BallSize / 5,c[a]); if I add instead of the circle movements it shows that it works but again starts right off the bat before it should. sorry I edit a lot. -I edit a lot. Prepare thyself. |
Marco Radaelli
Member #3,028
December 2002
|
Quote: What kind of things might cause this. A deadlock happens when two subjects cross they need for objects. Example, you have P1, P2 which are processes and R1, R2 which are resources. P1 owns R1 and needs R2, P2 owns R2 and needs R1. You have a deadlock because none of the processes can go on until the other releases the resource it's owning.
|
ImLeftFooted
Member #3,935
October 2003
|
I would suggest you skip threading entirely and then come back to it later. If you can't do that, then I would start off with some dead simple thread programs and work your way up. This app is a tad complicated. |
CIRCLE
Member #5,301
December 2004
|
Taking the easy way is never my thing. I got it working and have isolated the problem. Now working around the problem is something else. If I use... circlefill(screen,xx[z],yy[z],BallSize / 5,c[z]); instead of... circlefill(active_page,xx[z],yy[z],BallSize / 5,c[z]); So my next question is how do I tell the multithread to hold off and wait till the main program is done. I assumed that would be done with pthread_mutex_lock and pthread_mutex_unlock but I guess I am wrong. Where would be a good place to learn about pthread? -I edit a lot. Prepare thyself. |
ImLeftFooted
Member #3,935
October 2003
|
It makes no sense whatsoever to use threads to handle paging. |
CIRCLE
Member #5,301
December 2004
|
I am using the thread to handle background graphics. Having some fun. The paging is done out side the thread. show_video_bitmap(active_page); if (active_page == buffer) active_page = buffer2; else active_page = buffer; clear_to_color(active_page, makecol(0, 0, 0)); question was on how to tell the threaded area of my program to hold on while the main program uses a resource. if I use for (z = 1; z < 1000; z++){ circlefill(active_page,xx[z],yy[z],BallSize / 5,c[z]); }
outside the threaded program it works fine. But the point is to get it to work inside the threaded area. -I edit a lot. Prepare thyself. |
nonnus29
Member #2,606
August 2002
|
Quote: Taking the easy way is never my thing. I got it working and have isolated the problem. Now working around the problem is something else. If you're not into 'easy things' then why are you asking these guys to write your code for you instead of you studying the relevant subject ie threads and communicating process with semaphores and mutexes? |
CIRCLE
Member #5,301
December 2004
|
Wow tons of help. I understand as to how they work not to why it is not working. another example which SHOULD lock variables till it is done but doesn't
but instead of helping find what seems to everyone else like a small mistake I get the run around. -I edit a lot. Prepare thyself. |
nonnus29
Member #2,606
August 2002
|
The point is it's not small, multi threading is really hard. Can anyone gurantee that allegro, or direct x or anything else isn't running a thread in the background that's causing deadlocks with your thread? I can't. |
GullRaDriel
Member #3,861
September 2003
|
I can. I use threads a lot with allegro, and all the deadlock I had were caused by me. "Code is like shit - it only smells if it is not yours" |
CIRCLE
Member #5,301
December 2004
|
This also a deadlock caused by me. Simple comment out showed me what was doing it aswell. If I just use a BITMAP that my main program does not have access to like "screen" then everything works fine. Only problem is it still slows the main program down where to my understanding each thread should have its own speed. -I edit a lot. Prepare thyself. |
GullRaDriel
Member #3,861
September 2003
|
Yeah, but if they both access the same critical section, they will wait each other to free the locked ressource before doing some stuff. "Code is like shit - it only smells if it is not yours" |
CIRCLE
Member #5,301
December 2004
|
I was also under the impression when I pthread_mutex_lock it would lock the resources it was using till pthread_mutex_unlock was passed both my main loop and my thread use this. While screen works both can not use active_page even when locking for some reason. If I could lock out the main loop from using the BITMAP active_page when the thread was using it things would be easier and vice versa. -I edit a lot. Prepare thyself. |
Kitty Cat
Member #2,815
October 2002
|
Locking a mutex prevents other threads from locking the same mutex. If a thread locks a mutex, and another tries to lock the same mutex, the second will block (wait) until the first thread unlocks the mutex. THis makes it so two threads can't touch the same data at the same time. Quote: my understanding each thread should have its own speed. When two threads handle the same data, they have to do syncronization (usually through mutexes) so they don't step on each others toes. This quickly leads to performance degradation on both parts. Using threads is not a recipe for speed. It's a tool to help make more efficient use of resources when properly handled. -- |
CIRCLE
Member #5,301
December 2004
|
Thanks to those that helped and gave advice. I was able to get my program to work. Although not entirely the way I wanted but work none the less. To GullRaDriel for pointing out that I may have a deadlock. Once figured out where was fairly easy to fix. Thanks. To Marco Radaelli for the explination of exactly what happens when a deadlock occurs. Thanks To Dustin Dettmer helping to get me to realize I am over my head To nonnus29 with that awsome link with all sorts of information about threads and much more. Thanks. Thanks for all the help. -Consider this thread closed. -I edit a lot. Prepare thyself. |
|