Thread ends = program ends? Why?

Good morning. I’m writing my first SDL application (combining parts
from various examples and test apps), which is intended (eventually)
to be a slide-show-to-music program. I’ve set up two threads, one
which will handle video, the other of which will handle audio.
There’s also the main thread, which currently isn’t doing anything
important.

This application works – for a while. As soon as the video thread
ends, the application exits even though the audio thread should still
be running. Furthermore, it seems to exit non-gracefully (although
without a core dump) in that if I run it full-screen, it does not
restore the screen resolution back to its original (under X on
Linux).

There does not appear to be a function that a thread should call to
exit itself gracefully; it seems that it is just supposed to return to
its caller. Is this incorrect? Is there a proper way to do it?

Why does the application exit when the video thread completes?
Application follows…

Thanks!

Derrell----------------------------------------------------------------------

#include <stdlib.h>
#include <stdio.h>

#include “SDL.h”
#include “SDL_thread.h”
#include “SDL_image.h”
#include “smpeg/smpeg.h”

#ifndef TRUE

define TRUE 1

define FALSE 0

#endif

#if 0
#define IMAGE_WIDTH 1024
#define IMAGE_HEIGHT 768
#else
#define IMAGE_WIDTH 640
#define IMAGE_HEIGHT 480
#endif

#define P puts

#define SLIDE “/winstuff/cap/mmcs/Slide Shows/Slides/199901-01/0022.jpg”
#define SOUND “/var/tmp/moon_landing.mp3”

static int
videoThread(void * pData)
{
int depth;
SDL_Surface * pScreen;
SDL_Surface * pImage;

/* Create a display for the image */
depth = SDL_VideoModeOK(IMAGE_WIDTH, IMAGE_HEIGHT, 32, SDL_SWSURFACE);

if ((pScreen = SDL_SetVideoMode(IMAGE_WIDTH,
			    IMAGE_HEIGHT,
			    depth,
			    (SDL_DOUBLEBUF |

#if 0
SDL_FULLSCREEN |
#endif
SDL_HWPALETTE |
SDL_HWSURFACE))) == NULL)
{
fprintf(stderr,“Couldn’t set %dx%dx%d video mode: %s\n”,
IMAGE_WIDTH, IMAGE_HEIGHT, depth, SDL_GetError());
SDL_Quit();
exit(1);
}

/* No cursor */
SDL_ShowCursor(0);

/* Open the image file */
if ((pImage = IMG_Load(SLIDE)) == NULL)
{
fprintf(stderr,"Couldn't load %s: %s\n", SLIDE, SDL_GetError());
SDL_Quit();
exit(1);
}

/* Set the palette, if one exists */
if (pImage->format->palette)
{
SDL_SetColors(pScreen, pImage->format->palette->colors,
	      0, pImage->format->palette->ncolors);
}

/* Display the image */
SDL_BlitSurface(pImage, NULL, pScreen, NULL);
SDL_Flip(pScreen);

SDL_Delay(5000);

#if 0 /* See if this is causing it to exit… Nope. Still exits. /
/
We’re done! */
SDL_FreeSurface(pImage);
#endif

P("videoThread leaving");
return 0;

}

static int
audioThread(void * pData)
{
SMPEG * hMpeg;
SMPEG_Info info;

if (SMPEG_error(hMpeg = SMPEG_new(SOUND, &info, TRUE)))
{
fprintf(stderr, "%s\n", SMPEG_error(hMpeg));
SMPEG_delete(hMpeg);
}

SMPEG_enableaudio(hMpeg, TRUE);
SMPEG_setvolume(hMpeg, 100);

/* Play it, and wait for playback to complete */
SMPEG_play(hMpeg);
while (SMPEG_status(hMpeg) == SMPEG_PLAYING)
{
SDL_Delay(1000/2);
}
SMPEG_delete(hMpeg);

return 0;

}

int main(int argc,
char *argv[])
{
int i;

#if 1 /* Do we need this? It’s function is not documented /
/
Initialize the SDL library for event thread */
if (SDL_Init(SDL_INIT_EVENTTHREAD) < 0)
{
fprintf(stderr,
“Couldn’t initialize SDL event thread: %s\n”,
SDL_GetError());
return 1;
}
#endif

/* Initialize the SDL library for audio */
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
{
fprintf(stderr,
	"Couldn't initialize SDL audio: %s\n",
	SDL_GetError());
return 1;
}

/* Initialize the SDL library for video */
if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
{
fprintf(stderr,
	"Couldn't initialize SDL video: %s\n",
	SDL_GetError());
return 1;
}

if ((SDL_CreateThread(videoThread, NULL)) == NULL)
{
fprintf(stderr, "Couldn't create video thread: %s\n", SDL_GetError());
return 1;
}

if ((SDL_CreateThread(audioThread, NULL)) == NULL)
{
fprintf(stderr, "Couldn't create audio thread: %s\n", SDL_GetError());
return 1;
}

P("About to delay");

SDL_Delay(3000);

P("Delay finished.");

/* Wait for any keyboard or mouse input */
for (i=SDL_NOEVENT; i<SDL_NUMEVENTS; ++i)
{
switch (i)
{
case SDL_KEYDOWN:
case SDL_MOUSEBUTTONDOWN:
case SDL_QUIT:
    /* Valid event, keep it */
    break;
default:
    /* We don't want this event */
    SDL_EventState((Uint8)i, SDL_IGNORE);
    break;
}
}

for (;;)
{
SDL_WaitEvent(NULL);
}

P("About to SDL_Quit() -- never gets here for some reason");

SDL_Quit();

P("See ya!");

return 0;

}

Derrell,

you’ve got to catch the end of life of your thread.

The right way is:

// beginning of program

/* init your stuff */

/* create video thread */

thread_video = SDL_CreateThread(thread_function_of_yours_video,ptr_to_data_of_yours_video);

/* test if thread created right */

/* create sound thread */

thread_sound = SDL_CreateThread(thread_function_of_yours_sound,ptr_to_data_of_yours_sound);

/* test if thread created right */

/* do stuff for main thread */

/* wait end of video thread */

SDL_WaitThread(thread_video,ptr_of_yours_video);

/* wait end of soud thread */

SDL_WaitThread(thread_sound,ptr_of_yours_sound);

SDL_Quit(0);

// end of program

A good page to look at is:
libsdl.org/intro/usingthreads.html

All the best!
Aurelien> ----- Original Message -----

From: Derrell Lipman [mailto:Derrell.Lipman@UnwiredUniverse.com]
Sent: Thursday, February 22, 2001 9:22 AM
To: sdl at lokigames.com
Subject: [SDL] Thread ends = program ends? Why?

Good morning. I’m writing my first SDL application (combining parts
from various examples and test apps), which is intended (eventually)
to be a slide-show-to-music program. I’ve set up two threads, one
which will handle video, the other of which will handle audio.
There’s also the main thread, which currently isn’t doing anything
important.

This application works – for a while. As soon as the video thread
ends, the application exits even though the audio thread should still
be running. Furthermore, it seems to exit non-gracefully (although
without a core dump) in that if I run it full-screen, it does not
restore the screen resolution back to its original (under X on
Linux).

There does not appear to be a function that a thread should call to
exit itself gracefully; it seems that it is just supposed to return to
its caller. Is this incorrect? Is there a proper way to do it?

Why does the application exit when the video thread completes?
Application follows…

Thanks!

Derrell


#include <stdlib.h>
#include <stdio.h>

#include “SDL.h”
#include “SDL_thread.h”
#include “SDL_image.h”
#include “smpeg/smpeg.h”

#ifndef TRUE

define TRUE 1

define FALSE 0

#endif

#if 0
#define IMAGE_WIDTH 1024
#define IMAGE_HEIGHT 768
#else
#define IMAGE_WIDTH 640
#define IMAGE_HEIGHT 480
#endif

#define P puts

#define SLIDE “/winstuff/cap/mmcs/Slide Shows/Slides/199901-01/0022.jpg”
#define SOUND “/var/tmp/moon_landing.mp3”

static int
videoThread(void * pData)
{
int depth;
SDL_Surface * pScreen;
SDL_Surface * pImage;

/* Create a display for the image */
depth = SDL_VideoModeOK(IMAGE_WIDTH, IMAGE_HEIGHT, 32, SDL_SWSURFACE);

if ((pScreen = SDL_SetVideoMode(IMAGE_WIDTH,
  		    IMAGE_HEIGHT,
  		    depth,
  		    (SDL_DOUBLEBUF |

#if 0
SDL_FULLSCREEN |
#endif
SDL_HWPALETTE |
SDL_HWSURFACE))) == NULL)
{
fprintf(stderr,“Couldn’t set %dx%dx%d video mode: %s\n”,
IMAGE_WIDTH, IMAGE_HEIGHT, depth, SDL_GetError());
SDL_Quit();
exit(1);
}

/* No cursor */
SDL_ShowCursor(0);

/* Open the image file */
if ((pImage = IMG_Load(SLIDE)) == NULL)
{

fprintf(stderr,“Couldn’t load %s: %s\n”, SLIDE, SDL_GetError());
SDL_Quit();
exit(1);
}

/* Set the palette, if one exists */
if (pImage->format->palette)
{

SDL_SetColors(pScreen, pImage->format->palette->colors,
0, pImage->format->palette->ncolors);
}

/* Display the image */
SDL_BlitSurface(pImage, NULL, pScreen, NULL);
SDL_Flip(pScreen);

SDL_Delay(5000);

#if 0 /* See if this is causing it to exit… Nope. Still exits. /
/
We’re done! */
SDL_FreeSurface(pImage);
#endif

P("videoThread leaving");
return 0;

}

static int
audioThread(void * pData)
{
SMPEG * hMpeg;
SMPEG_Info info;

if (SMPEG_error(hMpeg = SMPEG_new(SOUND, &info, TRUE)))
{

fprintf(stderr, “%s\n”, SMPEG_error(hMpeg));
SMPEG_delete(hMpeg);
}

SMPEG_enableaudio(hMpeg, TRUE);
SMPEG_setvolume(hMpeg, 100);

/* Play it, and wait for playback to complete */
SMPEG_play(hMpeg);
while (SMPEG_status(hMpeg) == SMPEG_PLAYING)
{

SDL_Delay(1000/2);
}
SMPEG_delete(hMpeg);

return 0;

}

int main(int argc,
char *argv[])
{
int i;

#if 1 /* Do we need this? It’s function is not documented /
/
Initialize the SDL library for event thread */
if (SDL_Init(SDL_INIT_EVENTTHREAD) < 0)
{
fprintf(stderr,
“Couldn’t initialize SDL event thread: %s\n”,
SDL_GetError());
return 1;
}
#endif

/* Initialize the SDL library for audio */
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
{

fprintf(stderr,
“Couldn’t initialize SDL audio: %s\n”,
SDL_GetError());
return 1;
}

/* Initialize the SDL library for video */
if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
{

fprintf(stderr,
“Couldn’t initialize SDL video: %s\n”,
SDL_GetError());
return 1;
}

if ((SDL_CreateThread(videoThread, NULL)) == NULL)
{

fprintf(stderr, “Couldn’t create video thread: %s\n”, SDL_GetError());
return 1;
}

if ((SDL_CreateThread(audioThread, NULL)) == NULL)
{

fprintf(stderr, “Couldn’t create audio thread: %s\n”, SDL_GetError());
return 1;
}

P("About to delay");

SDL_Delay(3000);

P("Delay finished.");

/* Wait for any keyboard or mouse input */
for (i=SDL_NOEVENT; i<SDL_NUMEVENTS; ++i)
{

switch (i)
{
case SDL_KEYDOWN:
case SDL_MOUSEBUTTONDOWN:
case SDL_QUIT:
/* Valid event, keep it /
break;
default:
/
We don’t want this event */
SDL_EventState((Uint8)i, SDL_IGNORE);
break;
}
}

for (;;)
{

SDL_WaitEvent(NULL);
}

P("About to SDL_Quit() -- never gets here for some reason");

SDL_Quit();

P("See ya!");

return 0;

}

Derrell,

you’ve got to catch the end of life of your thread.

Also note that your code won’t work on Windows. All graphics calls
must be done in the main thread.

See ya,
-Sam Lantinga, Lead Programmer, Loki Entertainment Software

That partially answers the question I had earlier. I quote:

"
Hi all,

I read in the SDL Doc project that this guideline:

“Don’t call SDL video/event functions ffrom separate threads”

Can someone tell me what’s the reason behind? Wouldn’t it make it easier to code one thread to deal with the events while the main thread takes care of some computing/video display?
"

How about a separate event handling thread? Would it work under Windows?
I develop mostly on Linux but I consider making my code as compatible with Windows as possible (don’t know why… just a gut feeling)

Aurelien> ----- Original Message -----

From: Sam Lantinga [mailto:slouken@devolution.com]
Sent: Thursday, February 22, 2001 12:52 PM
To: sdl at lokigames.com
Subject: Re: [SDL] Thread ends = program ends? Why?

Derrell,

you’ve got to catch the end of life of your thread.

Also note that your code won’t work on Windows. All graphics calls
must be done in the main thread.

See ya,
-Sam Lantinga, Lead Programmer, Loki Entertainment Software

Aurelien Marchand <aurelien.marchand at researchcapital.com> writes:

Derrell,

you’ve got to catch the end of life of your thread.

Ok, thanks!

and then Sam Lantinga writes:

Also note that your code won’t work on Windows. All graphics calls
must be done in the main thread.

Actually, while I was awaiting responses, I moved the code to Windows
(running under Cygwin/gcc environment) and not only does it work, the
problem of the application ending when the first thread ends goes
away. The same application that failed under Linux works under
Winblows. Curious.

I’ll fix both problems (await completion of thread and move video
stuff to main thread).

Thanks for your help!

Derrell

ps. Patches to 1.1.8 for Cygwin build environment coming soon.

Why is this so?–

Olivier A. Dagenais - Software Architect and Developer

“Sam Lantinga” wrote in message
news:E14VzuZ-0000Lk-00 at roboto.devolution.com

Derrell,

you’ve got to catch the end of life of your thread.

Also note that your code won’t work on Windows. All graphics calls
must be done in the main thread.

See ya,
-Sam Lantinga, Lead Programmer, Loki Entertainment Software