Reputation: 38897
I have a thread called mainloop
i.e.
int run_mainloop;
void* mainloop(void* param)
{
// local vars
// initialize local vars
while(run_mainloop)
{
// run mainloop
}
return 0;
}
The thread is kicked off from a function called client_open
, i.e.
int client_open()
{
run_mainloop = 1;
return pthread_create(&thread, NULL, mainloop, NULL);
}
However, in mainloop
if initializing local variables fails I need to inform client_open
right away of early exit.
pthread_join
is inappropriate as it will block and I can't have client_open
block.
If it was to wait a short time before returning that would be ok.
How could I do this in a nice way without using pthread_join which will block. I want to be able to get the return code.
Upvotes: 5
Views: 1891
Reputation: 38897
Ok, I discovered three ways to do this.
1) Initialize and pass variables to mainloop before starting it.
2) Use the Linux specific pthread_tryjoin_np() or pthread_timedjoin_np() I think the timed join version is more appropriate in this case as it allows time for the thread to be created and for initialisation to be done. The timeout need not be long so it will not block the caller to client_open() for very long.
However, as pointed out by @fge they are non-portable. While that isn't too much of a problem I thought about an alternative way which is this.
EDIT: Not such a good solution, but left in here for reference. It'd be better to signal to open using a condition variable that initialization was ok.
3) Check if run_mainloop is non-zero, if it is and pthread_create didn't fail and the thread is running. If it's still zero after a time then it didn't start so we call pthread_join to get the exit code.
int run_mainloop = 0;
void* mainloop(void* param)
{
// init vars
// if failure, exit early.
// everything from this point on is good.
run_mainloop = 1;
while (run_mainloop))
{
// do styff
}
return 0;
}
int client_open()
{
void* res;
int rc = pthread_create(&g_thread_id, NULL, mainloop, NULL);
if (rc != 0)
return -1;
usleep(100); // wait a little while, kinda dumb but allows time for init
if (run_mainloop))
return 0;
pthread_join(g_thread_id, &res);
return -1;
}
Upvotes: -1
Reputation: 136256
You can use something known as completion variables.
Using which a thread can wait till a newly created thread has finished initialization. The only catch is that the new thread must always signal its initialization completion, even when initialization fails.
Something along the following lines (error handling omitted for clarity):
#include <pthread.h>
// Completion variable definition:
typedef struct {
pthread_mutex_t mtx;
pthread_cond_t cnd;
int completed;
int return_code;
} Completion;
#define COMPLETION_INIT { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
int completion_wait(Completion* c) { // add timeout if necessary
pthread_mutex_lock(&c->mtx);
while(!c->completed)
pthread_cond_wait(&c->cnd, &c->mtx);
int return_code = c->return_code;
pthread_mutex_unlock(&c->mtx);
return return_code;
}
void completion_signal(Completion* c, int return_code) {
pthread_mutex_lock(&c->mtx);
c->completed = 1;
c->return_code = return_code;
pthread_cond_signal(&c->cnd);
pthread_mutex_unlock(&c->mtx);
}
// Usage:
void* mainloop(void* vc) {
int init_success = 0;
// initialization
// ...
init_success = 1;
init_end:
Completion* c = (Completion*)vc;
completion_signal(c, init_success); // always signal
if(!init_success)
return NULL;
// start the main loop
return NULL;
}
int client_open()
{
int run_mainloop = 1;
pthread_t thread;
Completion c = COMPLETION_INIT;
pthread_create(&thread, NULL, mainloop, &c);
pthread_detach(thread);
return completion_wait(&c);
}
Upvotes: 4
Reputation: 213526
Using pthread_tryjoin_np
would be incorrect: the new thread could be arbitrarily delayed between pthread_create
return, and the new thread actually executing initialization code.
If you pthread_tryjoin_np
during that delay, the join will fail and you will decide that everything is "a-ok", when in fact it isn't.
What you want is a condition: client_open
will await on it, and the mainloop
will signal it (upon being done with initialization).
Upvotes: 4