二 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;}

推荐阅读