
Click the blue text above to follow us
In Linux multithreading programming, specific cleanup operations can be performed when a thread terminates by registering a thread cleanup handler.
This is similar to using atexit() to register process termination handlers.
The thread cleanup handler is used to perform resource release or cleanup tasks when a thread exits, such as closing file descriptors, releasing memory, etc.
Unlike processes, threads can register multiple cleanup handlers, which are managed in a stack structure—a last-in-first-out data structure.
Therefore, the execution order of cleanup handlers is the reverse of the registration order.
In Linux, the pthread_cleanup_push() and pthread_cleanup_pop() functions are used to add and remove cleanup handlers from the thread’s cleanup handler stack.
The prototypes are as follows:
void pthread_cleanup_push(void (*routine)(void *), void *arg);void pthread_cleanup_pop(int execute);
Parameter descriptions:
-
pthread_cleanup_push(): Used to push a cleanup handler onto the stack.
-
routine: A function pointer to the cleanup handler, which has no return value and accepts a void * parameter.
-
arg: The argument passed to the cleanup handler, which serves as input to routine() when the cleanup handler is executed.
-
pthread_cleanup_pop(): Used to pop the most recently added cleanup handler from the cleanup handler stack.
-
execute: Specifies whether to execute the cleanup handler. If it is 0, only the cleanup handler is removed without execution; if non-zero, the cleanup handler is removed and executed.
Scenarios for executing thread cleanup handlers:
-
When a thread calls pthread_exit() to exit, the cleanup handlers are executed automatically.
-
When a thread responds to a cancel request (e.g., by canceling the thread with pthread_cancel()), the cleanup handlers are executed.
-
When pthread_cleanup_pop() is called with a non-zero argument, the top cleanup handler on the stack is executed.
The following code demonstrates how to register and remove cleanup handlers using pthread_cleanup_push() and pthread_cleanup_pop():
void cleanup(void *arg) { printf("Cleaning up: %s\n", (char *)arg);}
void *thread_function(void *arg) { pthread_cleanup_push(cleanup, "Resource 1"); pthread_cleanup_push(cleanup, "Resource 2");
// Simulate thread work printf("Thread is running...\n");
// Calling pthread_exit() will trigger cleanup handler execution pthread_exit(NULL);
// Cleanup handlers must be used in pairs, so even after exit, pthread_cleanup_pop must be called pthread_cleanup_pop(1); pthread_cleanup_pop(1);}
int main() { pthread_t thread;
// Create a thread if (pthread_create(&thread, NULL, thread_function, NULL) != 0) { perror("Failed to create thread"); return 1; }
// Wait for the thread to finish pthread_join(thread, NULL); return 0;}
Explanation:
-
Two cleanup handlers are registered in the thread, namely “Resource 1” and “Resource 2”.
-
When the thread calls pthread_exit(), the cleanup handlers in the stack are executed in last-in-first-out order, so it will first print “Cleaning up: Resource 2”, then print “Cleaning up: Resource 1”.
Notes:
-
pthread_cleanup_push() and pthread_cleanup_pop() are not ordinary functions but are implemented as macros, and must appear in pairs within the same scope. They cannot be used separately in the code.
-
Cleanup handlers will only be executed when the thread exits via pthread_exit() or responds to a cancel request.
If a thread exits via a return statement, the cleanup handlers will not be executed.
By using pthread_cleanup_push() and pthread_cleanup_pop(), you can ensure that the necessary cleanup operations are executed when a thread terminates, which is very useful in resource management and exception handling.
The automatic execution of cleanup handlers makes resource release in multithreading programming more concise and secure.

