PDA

View Full Version : SDL Threads



maker3
13-02-2007, 12:33 AM
Hi all. Im studying Threads. I tried to run some examples but one i didnt get.

This example ok:

uses
SDL;

{$APPTYPE CONSOLE}
var
thread: PSDL_Thread;
returnValue: Integer;

function thread_func(): Integer;
begin
// do threading here
WriteLn('Start Thread');
SDL_Delay(5000);
WriteLn('End Thread');

result := 1; // thread leaves and return this value
end;

begin
returnValue := 0;
thread := SDL_CreateThread(@thread_func, NIL);

SDL_WaitThread(thread, returnValue);
WriteLn('Thread returns code ',returnValue);

SDL_Quit;
WriteLn('ByeBye ;)');
end.

But this, i get error. why? What is wrong? This example I ported from Lazy Foo's tutorial.

program teste;

{$APPTYPE CONSOLE}

uses
sdl,
sdlutils,
sdl_image;


const
SCREEN_WIDTH = 640;
SCREEN_HEIGHT = 480;
SCREEN_BPP = 32;

var
screen,image: PSDL_Surface;
event: TSDL_Event;
thread: PSDL_Thread;
quit: boolean = false;



function load_image(filename: string; setcolorkey: boolean) : PSDL_Surface; overload;
var
optimizedImage, loadedImage: PSDL_Surface;
r,g,b: uint8;

begin
loadedImage := IMG_Load(pchar(filename));

if &#40;loadedImage <> nil&#41; then
begin
optimizedImage &#58;= SDL_DisplayFormat&#40;loadedimage&#41;;
SDL_FreeSurface&#40;loadedimage&#41;;
if &#40;optimizedImage <nil> 0&#41; do
begin
case event.type_ of
SDL_QUITEV&#58;
quit&#58;= true;
end;
end;
clean_up;
end;

end.

Sorry my english.

maker3
13-02-2007, 12:38 AM
I dont know why the second code I posted is not completed. I think there are a bug in " [ code ] [ / code ]"

The second code


program teste;

{$APPTYPE CONSOLE}

uses
sdl,
sdlutils,
sdl_image;


const
SCREEN_WIDTH = 640;
SCREEN_HEIGHT = 480;
SCREEN_BPP = 32;

var
screen,image: PSDL_Surface;
event: TSDL_Event;
thread: PSDL_Thread;
quit: boolean = false;



procedure apply_surface(x, y: integer; source,destination: PSDL_Surface);
var
offset: SDL_Rect;

begin
//Get offsets
offset.x := x;
offset.y := y;

//Blit
SDL_BlitSurface( source, nil, destination, @offset );
end;


function init: boolean;
begin
//Initialize all SDL subsystems
if( SDL_Init( SDL_INIT_EVERYTHING ) = -1 ) then
begin
result:= false;
exit;
end;

//Set up the screen
screen := SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );

//If there was in error in setting up the screen
if( screen = nil ) then
begin
result:= false;
exit;
end;

//Set the window caption
SDL_WM_SetCaption( 'Thread test', nil );

//If everything initialized fine
result:= true;
end;


function load_files: boolean;
begin
//Load the image
image := load_image('image.png',true);

//If there was an error in loading the image
if( image = niL ) then
begin
result:= false;
exit;
end;

//If everything loaded fine
result:= true;
end;

procedure clean_up;
begin
//Stop the thread
SDL_KillThread( thread );

//Free the surface
SDL_FreeSurface( image );

//Quit SDL
SDL_Quit();
end;

function my_thread(): integer;
begin
//While the program is not over
while( quit = false ) do
begin
//Do the caption animation
SDL_WM_SetCaption( 'Thread is running', nil );
SDL_Delay( 250 );

SDL_WM_SetCaption( 'Thread is running.', nil );
SDL_Delay( 250 );

SDL_WM_SetCaption( 'Thread is running..', nil );
SDL_Delay( 250 );

SDL_WM_SetCaption( 'Thread is running...', nil );
SDL_Delay( 250 );
end;

result:= 0;
end;


begin
//Initialize
if (init = false ) then
begin
exit;
end;

//Load the files
if( load_files = false ) then
begin
exit;
end;

//Create and run the thread
thread := SDL_CreateThread(@my_thread, nil );

//Apply the image to the screen
apply_surface( 0, 0, image, screen);

//Update the screen
if( SDL_Flip( screen ) = -1 ) then
begin
exit;
end;


while (quit = false) do
begin
while (SDL_PollEvent(@event) > 0) do
begin
case event.type_ of
SDL_QUITEV:
quit:= true;
end;
end;
clean_up;
end;

end.

maker3
13-02-2007, 09:20 AM
I founded the error.

:oops: :oops: :oops:

jdarling
13-02-2007, 02:37 PM
I founded the error.

:oops: :oops: :oops:

The fact that your returning false from your thread method instead of 1 to let SDL know that you initialized the thread properly? If not, post your solution to help others out too :)

maker3
13-02-2007, 04:20 PM
Hi jdarling.

The problem is the function clean_up. It must be out the while loop. :oops:
I dont know why I posted it there.



...

while (quit = false) do
begin
while (SDL_PollEvent(@event) > 0) do
begin
case event.type_ of
SDL_QUITEV:
quit:= true;
end;
end;
end;
clean_up;
end.



I have translated the "Fast Event Processing in SDL" (Bob Pendleton - about using Threads) from http://www.gameprogrammer.com/fastevents/fastevents1.html. But is not correct yet. I will post soon when I finish.

technomage
13-02-2007, 08:08 PM
I have already converted that code to pascal. I just havne't got round to adding it to the JEDI-SDL stuff yet... sorry :oops:


unit FastEvents;

interface

uses SDL;

const

FASTEVENT_ERROR = -1;
FASTEVENT_OK = 0;

procedure Fast_PumpEvents;
function Fast_PollEvent(Event: PSDL_Event): UInt32;
function Fast_WaitEvent(Event: PSDL_Event): UInt32;
function Fast_PushEvent(Event: PSDL_Event): UInt32;

function Fast_GetError: string;

implementation

var
EventLock: PSDL_Mutex;
EventWait: PSDL_cond;
EventTimer: PSDL_TimerID;
Error: string;

{------------------------------------------------------------------------------}
{Thread Safe Pump Events}
{------------------------------------------------------------------------------}
procedure Fast_PumpEvents;
begin
SDL_LockMutex(eventLock);
SDL_PumpEvents();
SDL_UnlockMutex(eventLock);
end;

{------------------------------------------------------------------------------}
{Poll Event Wrapper}
{------------------------------------------------------------------------------}
function Fast_PollEvent(Event: PSDL_Event): UInt32;
begin
SDL_LockMutex(eventLock);
Result := SDL_PollEvent(event);
SDL_UnlockMutex(eventLock);
if (Result > 0) then
begin
SDL_CondSignal(eventWait);
end
end;

{------------------------------------------------------------------------------}
{Wait Event Wrapper}
{------------------------------------------------------------------------------}
function Fast_WaitEvent(Event: PSDL_Event): UInt32;
begin
Result := 0;
SDL_LockMutex(eventLock);
while (SDL_PollEvent(event) <= 0) do
begin
SDL_CondWait(eventWait, eventLock);
end;
SDL_UnlockMutex(eventLock);
SDL_CondSignal(eventWait);
end;

{------------------------------------------------------------------------------}
{Push Event Wrapper}
{------------------------------------------------------------------------------}
function Fast_PushEvent(Event: PSDL_Event): UInt32;
begin
SDL_LockMutex(EventLock);
while (SDL_PushEvent(Event) <= 0) do
begin
SDL_CondWait(eventWait, eventLock);
end;
SDL_UnlockMutex(eventLock);
SDL_CondSignal(eventWait);
Result := 1;
end;

{------------------------------------------------------------------------------}
{Get Error function }
{------------------------------------------------------------------------------}
function Fast_GetError: string;
begin
Result := Error;
end;

procedure Fast_SetError(const Value: string);
begin
Error := Value;
end;

{------------------------------------------------------------------------------}
{Time Callback to wake up all waiting threads}
{------------------------------------------------------------------------------}
function timerCallback(interval: UInt32; param: Pointer): UInt32;
cdecl;
begin
SDL_CondBroadcast(EventWait);
Result := interval;
end;

{------------------------------------------------------------------------------}
{Initialization- creates timers and mutexs}
{------------------------------------------------------------------------------}
function FastEventsInit: Integer;
begin
Result := FASTEVENT_ERROR;
if (SDL_INIT_TIMER and SDL_WasInit(SDL_INIT_TIMER) = 0) then
begin
SDL_InitSubSystem(SDL_INIT_TIMER);
end;
EventLock := SDL_CreateMutex;
if (EventLock = nil) then
begin
Fast_SetError('Fast Events: cannot create a mutex');
Exit;
end;
EventWait := SDL_CreateCond();
if (EventWait = nil) then
begin
Fast_SetError('Fast Events: cannot create a condition variable');
Exit;
end;
EventTimer := SDL_AddTimer(10, timerCallback, nil);
if (EventTimer = nil) then
begin
Fast_SetError('Fast Events: cannot add a timer');
Exit;
end;
Result := FASTEVENT_OK;
end;

{------------------------------------------------------------------------------}
{Clean Up}
{------------------------------------------------------------------------------}
procedure FastEventsQuit;
begin
SDL_DestroyMutex(eventLock);
eventLock := nil;
SDL_DestroyCond(eventWait);
eventWait := nil;
SDL_RemoveTimer(eventTimer);
end;


initialization

FastEventsInit;

finalization

FastEventsQuit;

end.

maker3
13-02-2007, 10:28 PM
Omg technomage oO

Its great. I will look later.

technomage, im looking for Network lib (UDP reliable) for my project too. I saw your article and I ask: SDL_net is a good alternative? Its not safe thread. There are another option? Indy is a good option? I would like to use one and implement the "UDP reliable". This same site there are the NET2, (a fast threaded event based networking - a second layer above SDL_net). But, I dont know where I may go. SDL_net? Indy? ...? I would like it can be to compiled in win / linux.

Sorry my english.

maker3
14-02-2007, 01:10 PM
I have translated quickly the thread4 to us can test the fastevents. But I think there are something wrong with the fastevents translated. It crash on the finalization.


fastevents.pas:


...

{------------------------------------------------------------------------------}
{Clean Up}
{------------------------------------------------------------------------------}
procedure FastEventsQuit;
begin
SDL_DestroyMutex(eventLock);
eventLock := nil;
SDL_DestroyCond(eventWait);
eventWait := nil; <= crash here
SDL_RemoveTimer(eventTimer);
end;



Thread4.pas:

program thread4;

{$APPTYPE CONSOLE}

uses
Sysutils,sdl,fastevents;

var
doneYet: integer = 0;
num: integer = 0;

type
nameValue = record
value: Uint32;
name: string;
end;

const
appFlags: array[0..2] of namevalue = (
(value:SDL_APPMOUSEFOCUS; name: 'SDL_APPMOUSEFOCUS'),
(value:SDL_APPINPUTFOCUS; name: 'SDL_APPINPUTFOCUS'),
(value:SDL_APPACTIVE; name: 'SDL_APPACTIVE')
);
numAppFlags = sizeof(appFlags) div sizeof(nameValue);


procedure printSDLEvent(e: PSDL_Event);
var
sym: PSDL_keysym;
i: integer;

begin
i:= 0;

case (e.type_) of
SDL_ACTIVEEVENT: //* Application loses/gains visibility */
begin
writeln('SDL_ACTIVEEVENT');
writeln(' gain =', e.active.gain);
writeln(' state =', e.active.state);
for i := 0 to numAppFlags-1 do
begin
if (0 <> (appFlags[i].value and e.active.state)) then
begin
writeln(Format(' =%02x,%s', [appFlags[i].value, appFlags[i].name]));
end;
end;
end;
SDL_KEYDOWN: //* Keys pressed */
begin
sym := @e.key.keysym;
writeln('SDL_KEYDOWN');
writeln(' which =', e.key.which);
writeln(' state =', e.key.state);
writeln(' scancode=', sym.scancode);
if (0 <sym> 0) then
begin
//* Is it a control-character? */
if (sym.unicode <ord>unicode & 0xFF00))
{
printf("(%c)", sym->unicode);
end;
#endif*)
end;
end;
writeln('');
end;
SDL_KEYUP: //* Keys released */
begin
sym := @e.key.keysym;
writeln('SDL_KEYUP');
writeln(' which =', e.key.which);
writeln(' state =', e.key.state);
writeln(' scancode=', sym.scancode);
if (0 <sym>mod);
writeln(' unicode =', sym.unicode);
if (sym.unicode > 0) then
begin
//* Is it a control-character? */
if (sym.unicode <ord>unicode & 0xFF00))
end;
printf("(%c)", sym->unicode);
end;
#endif*)
end;
end;
writeln('');
end;
SDL_MOUSEMOTION: //* Mouse moved */
begin
writeln('SDL_MOUSEMOTION');
writeln(' which =', e.motion.which);
writeln(' state =', e.motion.state);
writeln(Format(' abs x,y =%d,%d', [e.motion.x,e.motion.y]));
writeln(Format(' rel x,y =%d,%d', [e.motion.xrel, e.motion.yrel]));
end;
SDL_MOUSEBUTTONDOWN: //* Mouse button pressed */
begin
writeln('SDL_MOUSEBUTTONDOWN');
writeln(' which =', e.button.which);
writeln(' button =', e.button.button);
writeln(' state =', e.button.state);
writeln(Format(' abs x,y =%d,%d', [e.motion.x, e.motion.y]));
end;
SDL_MOUSEBUTTONUP: //* Mouse button released */
begin
writeln('SDL_MOUSEBUTTONUP');
writeln(' which =', e.button.which);
writeln(' button =', e.button.button);
writeln(' state =', e.button.state);
writeln(Format(' abs x,y =%d,%d', [e.motion.x, e.motion.y]));
end;
(* case SDL_JOYAXISMOTION: /* Joystick axis motion */
printf("SDL_JOYAXISMOTION\n");
printf(" which =%d\n", (Uint32)e->jaxis.which);
printf(" axis =%d\n", (Uint32)e->jaxis.axis);
printf(" value =%d\n", (Sint32)e->jaxis.value);
break;

case SDL_JOYBALLMOTION: /* Joystick trackball motion */
printf("SDL_JOYBALLMOTION\n");
printf(" which =%d\n", (Uint32)e->jball.which);
printf(" ball =%d\n", (Uint32)e->jball.ball);
printf(" rel x,y =%d,%d\n", (Sint32)e->jball.xrel, (Sint32)e->jball.yrel);
break;

case SDL_JOYHATMOTION: /* Joystick hat position change */
printf("SDL_JOYHATMOTION\n");
printf(" which =%d\n", (Uint32)e->jhat.which);
printf(" hat =%d\n", (Uint32)e->jhat.hat);
printf(" value =%d\n", (Sint32)e->jhat.value);
break;

case SDL_JOYBUTTONDOWN: /* Joystick button pressed */
printf("SDL_JOYBUTTONDOWN\n");
printf(" which =%d\n", (Uint32)e->jbutton.which);
printf(" button =%d\n", (Uint32)e->jbutton.button);
printf(" state =%01x\n", (Uint32)e->jbutton.state);
break;

case SDL_JOYBUTTONUP: /* Joystick button released */
printf("SDL_JOYBUTTONUP\n");
printf(" which =%d\n", (Uint32)e->jbutton.which);
printf(" button =%d\n", (Uint32)e->jbutton.button);
printf(" state =%01x\n", (Uint32)e->jbutton.state);
break;
*)
SDL_QUITEV: //* User-requested quit */
writeln('SDL_QUIT');
SDL_SYSWMEVENT: //* System specific event */
writeln('SDL_SYSWMEVENT');
SDL_VIDEORESIZE: //* User resized video mode */
begin
writeln('SDL_VIDEORESIZE');
writeln(Format(' w,h =%d,%d', [e.resize.w, e.resize.h]));
end;
SDL_VIDEOEXPOSE: //* Screen needs to be redrawn */
writeln('SDL_VIDEOEXPOSE');
else
begin
if ((SDL_USEREVENT <= e.type_) and (e.type_ <SDL_NUMEVENTS> 0)) do
begin
ev.user.data1 := pointer(i);
val := Fast_PushEvent(@ev);
inc(num);
//writeln('send=',num);
inc(i);
end;

result:= 0;
end;


var
count: integer = 0;
rate: double = 0.0;
start: Uint32 = 0;
end_: Uint32 = 0;
limit: Uint32 = (10 * 1000);
thread: PSDL_Thread;
ev: TSDL_Event;
i: integer;
sym: PSDL_keysym;

begin


(* if (2 <= argc)
{
limit = 1000 * atoi(argv[1]);
end;
*)
limit := 1000 * 1;
SDL_Init({SDL_INIT_EVENTTHREAD or} SDL_INIT_VIDEO or SDL_INIT_NOPARACHUTE);


thread := SDL_CreateThread(@runThread, nil);

start := SDL_GetTicks;
while ((SDL_GetTicks() <start> 0)) do
begin
dec(num);
// writeln('got=', num);
// writeln('time=',SDL_GetTicks());
case (ev.type_) of
SDL_USEREVENT:
begin
i:= integer(ev.user.data1);
// writeln(Format('count=%d data1=%d', [count,i]));
inc(count);
end;
SDL_QUITEV:
begin
writeln('got here');
exit; // this isn't supposed to happen
end;
else
begin
printSDLEvent(@ev);
end;
end;
end;
doneYet := 1;

while (Fast_PollEvent(@ev) > 0) do // drain the que
begin
end;

// SDL_WaitThread(@thread,nil); // wait for it to die
SDL_WaitThread(@thread,i); // wait for it to die

end_ := SDL_GetTicks();

rate := count / ((end_ - start) / 1000);
writeln('events/second=', rate);
SDL_Quit;
end.

technomage
14-02-2007, 11:06 PM
Mmm. Never had a crash on the projects I've used this on....

better look at the translation again and see if there is anything I missed.