---
# System prepended metadata

title: Pthread return value 探討

---

# **Pthread return value 探討**



根據"並行和多執行緒程式設計課程"裡的 POSIX Thread 章節
https://hackmd.io/@sysprog/concurrency/%2F%40sysprog%2Fposix-threads

其中程式碼：
```
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void printMsg(char *msg)
{
    int *status_c = malloc(sizeof(int));
    *status_c = 1;
    printf("%s\n", msg);
    pthread_exit(status_c);
}

int main(int argc, char **argv)
{
    pthread_t thrdID;
    int *status_p = malloc(sizeof(int));

    printf("creating a new thread\n");
    pthread_create(&thrdID, NULL, (void *) printMsg, argv[1]);
    printf("created thread %lu\n", thrdID);
    pthread_join(thrdID, (void**) &status_p);
    printf("Thread %lu exited with status %d\n", thrdID, *status_p);

    return 0;
}
```
方便起見, 我們修改變數名稱為 status_c 和 status_p
分別代表child/parent 宣告的return value pointer

其中main 裡面的宣告接收thread return value的參數
```
int *status_p = malloc(sizeof(int));
```
真的需要額外再malloc 一個空間嗎？
```
pthread_join(thrdID, (void**) &status_p);
```
究竟是把thread status_c 複製一份到 status_p  還是 
讓status_p 指向status_c?

可觀察pthread_join 定義
```
int pthread_join(pthread_t thread, void **retval);
```

retval 為pointer of pointer, 合理推測其行為應是"讓status_p 指向status_c"

# **gdb 驗證：**
```
chandler@lima-default:~/Embedded_Class/week3/pthread$ gdb -q --args pthread "Hello"
Reading symbols from pthread...
(gdb) l
1       #include <stdio.h>
2       #include <stdlib.h>
3       #include <pthread.h>
4
5       void printMsg(char *msg)
6       {
7           int *status_c = malloc(sizeof(int));
8           *status_c = 1;
9           printf("%s\n", msg);
10          pthread_exit(status_c);
(gdb) l
11      }
12
13      int main(int argc, char **argv)
14      {
15          pthread_t thrdID;
16          int *status_p = malloc(sizeof(int));
17
18          printf("creating a new thread\n");
19          pthread_create(&thrdID, NULL, (void *) printMsg, argv[1]);
20          printf("created thread %lu\n", thrdID);
(gdb) l
21          pthread_join(thrdID, (void**) &status_p);
22          printf("Thread %lu exited with status %d\n", thrdID, *status_p);
23
24          return 0;
25      }

Breakpoint 2, main (argc=2, argv=0xfffffffff258) at pthread.c:18
18          printf("creating a new thread\n");
(gdb) p status_p
$1 = (int *) 0xaaaaaaac12a0
(gdb) c
Continuing.
creating a new thread
[New Thread 0xfffff7dff1a0 (LWP 35473)]
created thread 281474840392096
[Switching to Thread 0xfffff7dff1a0 (LWP 35473)]

Thread 2 "pthread" hit Breakpoint 1, printMsg (msg=0xfffffffff52e "Hello") at pthread.c:8
8           *status_c = 1;
(gdb) p status_c
$2 = (int *) 0xfffff0000b70
(gdb) c
Continuing.
Hello
[Thread 0xfffff7dff1a0 (LWP 35473) exited]
[Switching to Thread 0xfffff7ff7ee0 (LWP 35470)]

Thread 1 "pthread" hit Breakpoint 3, main (argc=2, argv=0xfffffffff258) at pthread.c:22
22          printf("Thread %lu exited with status %d\n", thrdID, *status_p);
(gdb) p status_p
$3 = (int *) 0xfffff0000b70
```

可觀察確實為修改指標

# 檢視glibc 裡的source code
https://sourceware.org/git/?p=glibc.git;a=blob;f=nptl/pthread_join.c;h=6a87a8b329c3e34a57d65e86d45fa97a5fdb2fe2;hb=HEAD
```
  99   if (__builtin_expect (result == 0, 1))
 100     {
 101       /* We mark the thread as terminated and as joined.  */
 102       pd->tid = -1;
 103 
 104       /* Store the return value if the caller is interested.  */
 105       if (thread_return != NULL)
 106         *thread_return = pd->result;
 107 
 108 
 109       /* Free the TCB.  */
 110       __free_tcb (pd);
 111     }
 112 
```

確實也是修改指標, 並沒有做memory copy 的動作

# 結論
main 裡的status_p 不應使用malloc
程式碼應改寫為
```
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void printMsg(char *msg)
{
    int *status_c = malloc(sizeof(int));
    *status_c = 1;
    printf("%s\n", msg);
    pthread_exit(status_c);
}

int main(int argc, char **argv)
{
    pthread_t thrdID;
    int *status_p;

    printf("creating a new thread\n");
    pthread_create(&thrdID, NULL, (void *) printMsg, argv[1]);
    printf("created thread %lu\n", thrdID);
    pthread_join(thrdID, (void**) &status_p);
    printf("Thread %lu exited with status %d\n", thrdID, *status_p);

    return 0;
}
```