@afxgroup
Hi, I noticed the cause for the hanging of threads.
I have not figured out exactly why or the elegant solution, but, in the situation where I have a simple program (known, now, as the "main thread") that then creates a thread (known, now, as the "child thread"); where, child thread loops constantly until some request from the main thread - in my case - pthraed_cancel(childThread);
In this case, it seems like (pthread_join.c):
Wait(SIGF_PARENT);
Will never receive the signal.
At (StartFunc / pthread_create.c)
Printf("[%s] Finishing stuff\n", inf->name);
the issue seems to be that
if (inf->status == THREAD_STATE_RUNNING) {
is NOT true. Then, no "Signal(inf->parent, SIGF_PARENT);" is performed.
In that case, the parent thread is left WAITING.
To test it, I hacked in
Forbid();
Signal(inf->parent, SIGF_PARENT);
to be executed - regardless. Now, child thread shuts down, which it does anyway, but also the main thread shuts down because it receives the signal.
===
Alternatively to modifying anything in the clib2/pthread branch, you can issue something like a Delay(150) between "pthread_cancel" and "pthread_join" in your own user program without adding any hacks to the current clib2/pthreads branch - and you may be able to see that in that case the main thread is also not left WAITING and that it successfully closes.
===
Here is the test code:
Can toggle the commenting of IDOS->Delay. Forget about the "sound thread" that was just some extra testing. Ofc, requires SDL2.
#include <SDL2/SDL.h>
#include <pthread.h>
#include <time.h>
#include <proto/dos.h> /* just for Delay */
#define MSG(msg) { fprintf(stderr,"%s\n",msg); fflush(stderr); }
#define BAIL(msg,ret) { MSG(msg) ; RET=ret; goto ENDER; }
int RET=0;
SDL_Window *window;
SDL_Renderer *render;
SDL_Event ev;
int quit=0;
int vel_x=3,vel_y=-2;
/* thread stuff*/
pthread_t thread_s;
pthread_t thread_e;
// void* thread_sound(void*);
void* thread_engine(void*);
int retval_sound,retval_engine;
Uint8 r=0xFF,g=0x00,b=0x00;
/* gfx */
SDL_Rect block = { 400,300,10,10};
int main(int argc, char *argv[])
{
(void)argc;(void)argv;
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO))
{
BAIL(SDL_GetError(),10);
}
if(SDL_CreateWindowAndRenderer(800,600,0/*no flags*/,&window,&render))
{
BAIL(SDL_GetError(),20);
}
SDL_SetWindowTitle(window,"thread_test");
// /* now let's create a thread for some sound */
// if(pthread_create(&thread_s,NULL,&thread_sound,NULL))
// {
// BAIL("Unable to create a thread for sound",30);
// }
/* and, a thread for some sort of engine */
if(pthread_create(&thread_e,NULL,&thread_engine,NULL))
{
BAIL("Unable to create a thread for engine",31);
}
while(!quit)
{
while(SDL_PollEvent(&ev))
{
if(ev.type == SDL_QUIT)
{
quit=1;
}
}
SDL_SetRenderDrawColor(render,0x00,0x00,0x00,0x00);
SDL_RenderClear(render); /* draw an empty black screen! */
SDL_SetRenderDrawColor(render,r,g,b,0x00);
SDL_RenderFillRect(render,&block);
SDL_RenderPresent(render);
SDL_Delay(33);
}
// /* we get here if we quit */
// if(pthread_cancel(thread_s))
// {
// BAIL("Failed to cancel sound thread!",40);
// }
/* we get here if we quit */
if(pthread_cancel(thread_e))
{
BAIL("Failed to cancel engine thread!",41);
}
else
{
printf("We canceled it!\n");
}
// /* wait for the thread to finish */
// if(pthread_join(thread_s,NULL))
// {
// BAIL("Could not join sound thread!",50);
// }
/*IDOS->Delay(150);*/
printf("Calling pthread_join!\n");
if(pthread_join(thread_e,NULL))
{
BAIL("Could not join engine thread!",51);
}
else
{
printf("We joined it!\n");
}
ENDER:
if(render) SDL_DestroyRenderer(render);
if(window) SDL_DestroyWindow(window);
SDL_Quit();
return RET;
}
// void* thread_sound(void* args)
// {
// (void)args;
// struct timespec ts;
// for(;;)
// {
// pthread_testcancel();
// if(clock_gettime(CLOCK_REALTIME,&ts))
// {
// MSG("Unsuccessful call to clock_gettime()");
// }
// printf("Time: %llu\n",ts.tv_sec);
// }
// }
void* thread_engine(void* args)
{
(void)args;
for(;;)
{
pthread_testcancel();
if((block.x > 800)||(block.x<0))
vel_x=-(vel_x);
if((block.y > 600)||(block.y<0))
vel_y=-(vel_y);
block.x+=vel_x;
block.y+=vel_y;
if(block.x>400)
{
r=0x00;
g=0x00;
b=0xFF;
}
else
{
r=0xFF;
g=0x00;
b=0x00;
}
}
}