I am using posix threads in C. I have two threads in my program, thread1 and thread2. thread1 starts thread2.
thread1 maintains a variable var1 based on which thread2 has to be exited safely.
thread2 calls many lengthy functions (whose runtime can be upto 5 sec). There are many memory allocations using malloc in thread2. As soon as var1 becomes true, I need to close thread2 but only after deallocating all allocated memories. How this can be done?
The code looks like this:
void * func1(void *arg)
{
pthread_create(&thread2, &attr, func2, NULL);
while(1)
{
// ...
var1 = func3();
if(var1 == true)
{
// Cancel thread2
}
// ...
}
}
void * func2(void *arg)
{
// ...
func4(); // runs for 2 sec
char* var2 = malloc(10);
func5(); // runs for 5 sec
char* var3 = malloc(20);
// ...
cleanup:
free(var2);
free(var3);
return (void*) 0;
}
There are several ways to accomplish that. Here's one:
From the perspective of thread1 you can simply use pthread_cancel
on thread2 when the time comes. But you'd need to restructure thread2 accordingly to make sure it has cancellation points at safe places. You'd also need to restructure how you hold your data to allow a cancellation callback to be called for thread2:
struct func2_data {
char *var2;
char *var3;
};
void func2_cleanup(void *vdata) {
struct func2_data *data = vdata;
free(data->var2);
free(data->var3);
}
void * func2(void *arg)
{
struct func2_data data = {
NULL, NULL
};
pthread_cleanup_push(func2_cleanup, &data);
// ....
func4();
data.var2 = malloc(10);
pthread_testcancel();
func5();
data.var3 = malloc(10);
pthread_testcancel();
// ....
pthread_cleanup_pop(1);
return NULL;
}
So what happens here?
All the pointers that need freeing are bundles together and initialized to NULL. This allows a call to free
to act upon them as no-op if the cleanup function is called prior to any single variable being assigned.
A callback is registered to free the pointers. That callback will be called at any cancellation point. Including when the thread returns from its handler function. So you don't need to take care of it explicitly there, other than calling pop.
Cancellation points are added with pthread_testcancel
, at various "safe" places. Thus allowing the thread to end prematurely between calculations. Add them as you see fit.