Home | Projects | Notes > Multi-Threading (POSIX Threads) > Joinable & Detached Threads
By using pthread_create()
API, we can specify the thread to be created in one of the following two modes:
Joinable thread
Detached thread
Resources of the joinable thread are not released until it joins the parent thread. Therefore, it would be a wrong design if a thread is created in a joinable mode and it never has a chance to join some other thread that is blocked at the joint point.
A joinable thread can be converted into detached thread while it is running, or vice versa.
If no mode is specified upon the thread creation, the thread will run on joinable mode by default.
A Joinable thread may return the result to the parent (joinee) thread at the time of joint.
Try and change the second argument of thread_create()
for thread 2 and 3 and monitor the result. You should be able to predict the result correctly.
xxxxxxxxxx
1011/*
2 * File Name : joinable_example.c
3 * Description : C program to demonstrate the use of joinable threads
4 * Author : Modified by Kyungjae Lee (Original: Abhishek Sagar)
5 * Date Created : 12/27/2022
6 */
7
8 /*
9 * Compile using:
10 * gcc -g -c joinable_example.c -o joinable_example.o
11 * gcc -g joinable_example.o -o joinable_example -lpthread
12 * Or simply using:
13 * gcc -g joinable_example.c -o joinable_example -lpthread
14 *
15 * Run using:
16 * ./joinable_example
17 */
18
19
20
21/* POSIX threads */
22/* pause(), sleep() */
23/* errno */
24
25/* returns the square of arg */
26void* thread_fn_callback(void *arg)
27{
28 int th_id = *(int*)arg;
29 free(arg);
30 int rc = 0;
31
32 /* loop to simulate the thread taking some time to complete its task */
33 while (rc != th_id)
34 {
35 printf("Thread %d doing some work\n", th_id);
36 sleep(1);
37 rc++;
38 }
39
40 int *result = calloc(1, sizeof(int)); /* must use the heap to return a value */
41 *result = th_id * th_id;
42
43 return (void*)result;
44}
45
46void thread_create(pthread_t *pthread_handle, int th_id)
47{
48 pthread_attr_t attr; /* pthread_attr_t is an opaque structure */
49
50 int *_th_id = calloc(1, sizeof(int));
51 *_th_id = th_id;
52
53 /* sets the 1st arg to the 2nd arg value (POSIX standard API) */
54 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
55 pthread_attr_init(&attr);
56
57 /* fork point */
58 pthread_create(pthread_handle, &attr, thread_fn_callback, (void*)_th_id);
59}
60
61pthread_t pthread2;
62pthread_t pthread3;
63
64int main(int argc, char *argv[])
65{
66 void *thread_result2; /* points to the result thread2 produces */
67 void *thread_result3; /* points to the result thread3 produces */
68
69 thread_create(&pthread2, 2); /* user-defined function (not POXIS standard) */
70 thread_create(&pthread3, 10); /* user-defined function (not POXIS standard) */
71
72 printf("main() blocked on pthread_join() API for thread2\n");
73
74 /* blocking point - waits on thread2's termination
75 * (by the time thread2 joins, its return value will be available in the heap memory
76 * pointed to by 'thread_result2') */
77 pthread_join(pthread2, &thread_result2);
78
79 if (thread_result2)
80 {
81 printf("Return value of thread2 = %d\n", *(int*)thread_result2);
82 free(thread_result2);
83 thread_result2 = NULL;
84 }
85
86 printf("main() blocked on pthread_join() API for thread3\n");
87
88 /* blocking point - waits on thread3's termination
89 * (by the time thread3 joins, its return value will be available in the heap memory
90 * pointed to by 'thread_result3') */
91 pthread_join(pthread3, &thread_result3);
92
93 if (thread_result3)
94 {
95 printf("Return value of thread3 = %d\n", *(int*)thread_result3);
96 free(thread_result3);
97 thread_result3 = NULL;
98 }
99
100 return 0;
101}
xxxxxxxxxx
161main() blocked on pthread_join() API for pthread2
2Thread 10 doing some work
3Thread 2 doing some work
4Thread 2 doing some work
5Thread 10 doing some work
6Thread 10 doing some work
7Return value of thread2 = 4
8main() blocked on pthread_join() API for thread3
9Thread 10 doing some work
10Thread 10 doing some work
11Thread 10 doing some work
12Thread 10 doing some work
13Thread 10 doing some work
14Thread 10 doing some work
15Thread 10 doing some work
16Return value of thread3 = 100
A child joinable thread upon termination joins all the threads which are blocked on pthread_join()
on former's thread handle (pthread_t
).
Any thread as well as the parent thread can invoke pthread_join()
to wait on any other joinable thread's termination. (Any thread can wait for the termination of any other joinable thread in the process).
Just note that pthread_join()
cannot wait on detached thread's termination.
Resources of the detached thread are released as soon as the thread terminates.
A detached thread can be converted into a joinable while it is running, or vice versa.
A detached thread does not return any result to its parent thread. It does its job and then terminate without notifying any other threads.
Create thread T as joinable when:
T is supposed to return some result to other threads
e.g., Map reduce
Some other threads in the process are interested in being notified of T's termination
Create thread T as detached when:
No return result from T is expected
Nobody bothers about its termination
T runs an infinite loop
e.g., Waiting for user input
e.g., Waiting for network packets
e.g., TCP server's worker thread interacting with TCP clients. (Detached threads can be used in this case depending on what the application wants to achieve.)
Sagar, A. (2022). Part A - Multithreading & Thread Synchronization - Pthreads [Video file]. Retrieved from https://www.udemy.com/course/multithreading_parta/