二 Pthread 并發編程( 二 )

上面的程序的輸出結果如下所示:
$ ./join.outthread is not a joinable thread or Another thread is already waiting to join with this thread在上面的程序當中我們在一個 detached 狀態的線程上使用 pthread_join 函數,因此函數的返回值是 EINVAL 表示線程不是一個 joinable 的線程 。
在上面的程序當中 pthread_self() 返回當前正在執行的線程,返回的數據類型是 pthread_t,函數 pthread_detach(thread) 的主要作用是將傳入的線程 thread 的狀態變成 detached 狀態 。
我們再來看一個錯誤的例子,我們在一個無效的線程上調用 pthread_join 函數
#include <stdio.h>#include <error.h>#include <errno.h>#include <pthread.h>#include <unistd.h>pthread_t t1, t2;void* thread_1(void* arg) {  int ret = pthread_detach(pthread_self());  sleep(2);  if(ret != 0)    perror("");  return NULL;}int main() {  pthread_create(&t1, NULL, thread_1, NULL);  sleep(1);  int ret = pthread_join(t2, NULL);  if(ret == ESRCH)    printf("No thread with the ID thread could be found.\n");  else if(ret == EINVAL) {    printf("thread is not a joinable thread or Another thread is already waiting to join with this thread\n");  }  return 0;}上面的程序的輸出結果如下:
$./oin01.outNo thread with the ID thread could be found.在上面的程序當中我們并沒有使用 t2 創建一個線程但是在主線程執行的代碼當中,我們使用 pthread_join 去等待他,因此函數的返回值是一個 EINVAL。
我們再來看一個使用 retval 例子:
#include <stdio.h>#include <pthread.h>#include <sys/types.h>void* func(void* arg){  pthread_exit((void*)100);  return NULL;}int main() {  pthread_t t;  pthread_create(&t, NULL, func, NULL);  void* ret;  pthread_join(t, &ret);  printf("ret = %ld\n", (u_int64_t)(ret));  return 0;}上面的程序的輸出結果如下所示:
$./understandthread/join03.outret = 100在上面的程序當中我們使用一個參數 ret 去獲取線程的退出碼 , 從上面的結果我們可以知道,我們得到了正確的結果 。
如果我們沒有在線程執行的函數當中使用 pthread_exit 函數當中明確的指出線程的退出碼,線程的退出碼就是函數的返回值 。比如下面的的程序:
#include <stdio.h>#include <pthread.h>#include <sys/types.h>void* func(void* arg){  return (void*)100;}int main() {  pthread_t t;  pthread_create(&t, NULL, func, NULL);  void* ret;  pthread_join(t, &ret);  printf("ret = %ld\n", (u_int64_t)(ret));  return 0;}上面的程序的輸出結果也是 100,這與我們期待的結果是一致的 。
獲取線程的棧幀和PC值在多線程的程序當中,每個線程擁有自己的棧幀和PC寄存器(執行的代碼的位置 , 在 x86_86 里面就是 rip 寄存器的值) 。在下面的程序當中我們可以得到程序在執行時候的三個寄存器 rsp, rbp, rip 的值,我們可以看到,兩個線程執行時候的輸出是不一致的,這個也從側面反映出來線程是擁有自己的棧幀和PC值的 。
#include <stdio.h>#include <pthread.h>#include <sys/types.h>u_int64_t rsp;u_int64_t rbp;u_int64_t rip;void find_rip() {  asm volatile(    "movq 8(%%rbp), %0;"    :"=r"(rip)::  );}void* func(void* arg) {  printf("In func\n");  asm volatile(             \    "movq %%rsp, %0;"       \    "movq %%rbp, %1;"       \    :"=m"(rsp), "=m"(rbp):: \  );  find_rip();  printf("stack frame: rsp = %p rbp = %p rip = %p\n", (void*)rsp, (void*)rbp, (void*) rip);  return NULL;}int main() {  printf("================\n");  printf("In main\n");  asm volatile(             \    "movq %%rsp, %0;"       \    "movq %%rbp, %1;"       \    :"=m"(rsp), "=m"(rbp):: \  );  find_rip();  printf("stack frame: rsp = %p rbp = %p rip = %p\n", (void*)rsp, (void*)rbp, (void*) rip);  printf("================\n");  pthread_t t;  pthread_create(&t, NULL, func, NULL);  pthread_join(t, NULL);  return 0;}

推薦閱讀