I was going through the man pages of pthread_join and its mentioned the following
"When a joinable thread terminates, its memory resources (thread
descriptor and stack) are not deallocated until another thread performs
pthread_join on it. Therefore, pthread_join must be called once for
each joinable thread created to avoid memory leaks."
The reason has for doing this has been mentioned as to avoid memory leaks. But, I am not sure why in the first place the resources for a particular thread need to be still kept upon its termination.
Jayaraj
The thread descriptor is kept around so the thread procedure return value could be retrieved through the second parameter of pthread_join(2). This is the same idea as with zombie processes.
Keeping the stack of terminated thread was probably a requirement of the particular thread library implementation at the time the API was formalized.
Related
when there are waiting semaphores of sem_wait method, I call the sem_destroy method on other thread. But waiting semaphore was not wake up.
In case of mutex, pthread_mutex_destroy was return the value EBUSY when there are some waiting threads.
however sem_destroy return 0 and errno was also set 0.
I want to destroy semaphore after calling sem_destroy to block access as destroyed semaphore and to wake up the waiting thread.
Semaphore handle of Window OS is possible.
please advise me. thank you.
POSIX says this about sem_destroy:
The effect of destroying a semaphore upon which other threads are currently blocked is undefined.
It specifically doesn't say that other threads are woken up. In fact, if sem_t contains a pointer to memory, what it almost certainly does do is free the memory, meaning you then have a use-after-free security problem. (Whether that is the case depends on your libc.)
The general approach of allocation for mutexes and semaphores is that they should be either allocated and freed with their relevant data structure, or they should be allocated before the relevant code needs them and then freed after the entire code is done with them. In C, you cannot safely deallocate data structures (e.g., with sem_destroy) that are in use.
If you want to wake up all users of the semaphore, you must increment it until all users have awoken. You can call sem_getvalue to determine if anyone is waiting on the semaphore and then call sem_post to increment it. Only then can you safely destroy it. Note that this can have a race condition, depending on your code.
However, note that you must be careful that the other code does not continue to use the semaphore after it's destroyed, such as by trying to re-acquire it in a loop. If you are careful to structure your code properly, then you can have confidence that this won't happen.
pthread_detach marks a thread so that when it terminates, its resources are automatically released without requiring the parent thread to call pthread_join. How can it do this? From the perspective of Linux in particular, there are two resources in particular I am curious about:
As an implementation detail, I would expect that if a wait system call is not performed on the terminated thread, then the thread would become a zombie. I assume that the pthread library's solution to this problem does not involve SIGCHLD, because (I think) it still works regardless of what action the program has specified to occur when SIGCHLD is received.
Threads are created using the clone system call. The caller must allocate memory to serve as the child thread's stack area before calling clone. Elsewhere on Stack Overflow, it was recommended that the caller use mmap to allocate the stack for the child. How can the stack be unmapped after the thread exits?
It seems to me that pthread_detach must somehow provide solutions to both of these problems, otherwise, a program that spawns and detaches many threads would eventually lose the ability to continue spawning new threads, even though the detached threads may have terminated already.
The pthreads library (on Linux, NPTL) provides a wrapper around lower-level primitives such as clone(2). When a thread is created with pthread_create, the function passed to clone is a wrapper function. That function allocates the stack and stores that information plus any other metadata into a structure, then calls the user-provided start function. When the user-provided start function returns, cleanup happens. Finally, an internal function called __exit_thread is called to make a system call to exit the thread.
When such a thread is detached, it still returns from the user-provided start function and calls the cleanup code as before, except the stack and metadata is freed as part of this since there is nobody waiting for this thread to complete. This would normally be handled by pthread_join.
If a thread is killed or exits without having run, then the cleanup is handled by the next pthread_create call, which will call any cleanup handlers yet to be run.
The reason a SIGCHLD is not sent to the parent nor is wait(2) required is because the CLONE_THREAD flag to clone(2) is used. The manual page says the following about this flag:
A new thread created with CLONE_THREAD has the same parent process as the process that made the clone call (i.e., like CLONE_PARENT), so that calls to getppid(2) return the same value for all of the threads in a thread group. When a CLONE_THREAD thread terminates, the thread that created it is not sent a SIGCHLD (or other termination) signal; nor can the status of such a thread be obtained using wait(2). (The thread is said to be detached.)
As you noted, this is required for the expected POSIX semantics to occur.
According to POSIX, a Thread ID can be reused if the original bearer thread finished. Therefore, would one need to use a mutex or semaphore when calling pthread_join()? Because, it could happen that the target thread, which one wants to join, already terminated and another thread with the same thread ID was created, before calling pthread_join() in the original thread. This would make the original thread believe that the target thread has not finished, although this is not the case.
I think you'll find this works much the same way as processes in UNIX. A joinable thread is not considered truly finished until something has actually joined it.
This is similar to the UNIX processes in that, even though they've technically exited, enough status information (including the PID, which cannot be re-used yet) hangs around until another process does a wait on it. Only after that point does the PID become available for re-use. This kind of process is called a zombie, since it's dead but not dead.
This is supported by the pthread_join documentation which states:
Failure to join with a thread that is joinable (i.e., one that is not detached), produces a "zombie thread". Avoid doing this, since each zombie thread consumes some system resources, and when enough zombie threads have accumulated, it will no longer be possible to create new threads (or processes).
and pthread_create, which states:
Only when a terminated joinable thread has been joined are the last of its resources released back to the system.
If I use pthread_create to start a thread, and in the parent thread I do not call pthread_join to synchronize, it will cause memory leaking?
If you pthread_detach() it, it will not.
If not, it has to hold some memory (i.e., a leak), as the return result has to be stored somewhere indefinitely, waiting for a possible pthread_join().
From pthread_join() man page :
When a joinable thread terminates, its memory resources (thread descriptor and stack) are not deallocated until thread performs pthread_join on it. Therefore, pthread_join must be called once for each joinable thread created to avoid memory leaks.
Does it mean i need to join each thread i create to prevent leaks? But joining blocks the caller.
Please, explain more.
You don't need to join a thread, but it is a good idea. Without calling pthread_join(), there is a possibility that the main() function will return before the thread terminates. In this case, pthread_join() makes the application wait until the other thread finishes processing. Plus, when you join the thread, it gives you the opportunity to check for return values and make sure that everything went smoothly, and it gives you the opportunity to clean up any resources you may have shared with the thread.
EDIT: A function that may be of interest to you is pthread_detach(). pthread_detach() allows the thread's storage to be cleaned up after the thread terminates, so there is no need to join the thread afterwards.