I am currently trying to implement threads using the Apache Portable Runtime. Everything works fine, except I am not really sure if I am doing it the way it's intended to do due to lack of documentation or examples.
I need two threads and signal handling to catch a CTRL-C on the console to cleanup my server and possibly the threads. This is my current approach:
// Define APR thread pool
apr_pool_t *pool;
// Define server
MyServer *server;
// Define threads
apr_thread_t *a_thread, *b_thread;
apr_status_t status;
static void * APR_THREAD_FUNC func_a(apr_thread_t * thread,
void *data) {
// do func_a stuff here
}
static void * APR_THREAD_FUNC func_b(apr_thread_t * thread,
void *data) {
// do func_b stuff here
}
// Cleanup before exit
void cleanup(int s) {
printf("Caught signal %d\n", s);
// Destroy thread pool
apr_pool_destroy(pool);
//apr_thread_exit(a_thread, APR_SUCCESS);
//apr_thread_exit(b_thread, APR_SUCCESS);
//apr_terminate();
// Stop server and cleanup
server->stopServer();
delete server;
exit(EXIT_SUCCESS);
}
int main(void) {
// Signal handling
signal(SIGINT, cleanup);
// Create server
server = MyServerFactory::getServerImpl();
bool success = server->startServer();
// Initialize APR
if (apr_initialize() != APR_SUCCESS) {
printf("Could not initialize\n");
return EXIT_FAILURE;
}
// Create thread pool
if (apr_pool_create(&pool, NULL) != APR_SUCCESS) {
printf("Could not allocate pool\n");
return EXIT_FAILURE;
}
// Create a_thread thread
if (apr_thread_create(&a_thread, NULL, func_a, NULL,
pool) != APR_SUCCESS) {
printf("Could not create a_thread\n");
return EXIT_FAILURE;
}
//Create b_thread thread
if (apr_thread_create(&b_thread, NULL, func_b, NULL,
pool) != APR_SUCCESS) {
printf("Could not create b_thread\n");
return EXIT_FAILURE;
}
// Join APR threads
apr_thread_join(&status, a_thread);
apr_thread_join(&status, b_thread);
return EXIT_SUCCESS;
}
This works more or less as expected. The only thing I am not really sure about is if the cleanup works fine.
The cleanup-function seems to be called more then one time (String "Caught signal.." appears more than one time on terminal). Is there a way to prevent this? Is this problematic?
I found more than one example for cleaning up APR threads after usage. Is my way sufficient or do I need some of the commented stuff? Or am I completely wrong?
APR thread cleanup is explained in decent detail in the threading section of the APR Tutorial. In order, the cleanup steps look like this:
apr_thread_exit()
in the thread itself. While Unix threads terminate automatically, Windows threads do not. Call this function for portability (and to a return a status, if necessary).apr_thread_join()
in the main thread to wait for the termination of all threads.apr_pool_destroy()
to free the main memory pool. (Child memory pools are freed with apr_thread_exit()
.)apr_terminate()
to release other resources (sockets, etc.). Note that simply calling exit()
in another thread without these final steps can cause crashes.They also have a brief sample program that demonstrates some of this stuff.
As for why your signal handler is firing twice, I don't think that has to do with APR. SIGINT is sent to parent and child processes, so I suspect MyServer
is forking a new process and both are invoking the handler.