上面的程序的输出结果如下所示:
$ ./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;}
推荐阅读
- 如何理解Java中眼花缭乱的各种并发锁?
- 百变大侦探三男二女剧本杀真相答案详解
- 十五二十猜拳怎么玩啊
- 十五二十猜拳怎么玩
- 抓包整理————ip 协议一[十二]
- 天涯明月刀怎么导入捏脸数据(天刀手游捏脸二维码图)
- Mysql InnoDB多版本并发控制MVCC
- C#多线程之线程基础篇
- 二十四 设计模式学习:Spring 中使用到的设计模式
- <二>掌握构造函数和析构函数