目录1 创建线程1.1 pthread_create2.2 pthread_self2 线程等待2.1 pthread_join3 线程终止3.1 pthread_exit3.2 pthread_cancel4 线程分离4.1 pthread_detach5 POSIX库5.1 线程ID及进程地址空间布局1 创建线程1.1 pthread_create1功能pthread_create是 POSIX 线程pthread库中用于创建新线程的函数它是 Linux 和其他类 Unix 系统中多线程编程的基础。2函数原型#include pthread.h int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);3函数参数thread输出型参数指向pthread_t类型的指针用于存储新线程的标识符线程创建成功后系统会将线程ID写入这个位置attr指向线程属性对象的指针用于设置线程属性如栈大小、调度策略等如果为NULL则使用默认属性start_routine线程启动后执行的函数指针函数形式应为void *func_name(void *arg)arg传递给start_routine的参数如果需要传递多个参数可以封装在结构体中4返回值成功返回 0失败返回错误代码不是设置errno5示例#include iostream #include unistd.h #include pthread.h // 线程执行入口 void* thread_func(void* args) { std::string str (char*)args; // 第二个循环 while(true) { printf(Second thread:%s pid:%d num:%d\n, str.c_str(), getpid(), num); sleep(1); } } int main() { pthread_t tid; // 创建线程 pthread_create(tid, nullptr, thread_func, (void*)pthread-1); // 主线程 // 第一个循环 while(true) { printf(Main thread pid:%d num:%d\n, getpid(), num); sleep(1); } return 0; }2.2 pthread_self1功能pthread_self是 POSIX 线程库中用于获取调用线程自身轻量级进程PID的函数2函数原型#include pthread.h pthread_t pthread_self(void);3返回值返回调用线程的线程标识符pthread_t类型2 线程等待如果主线程结束就代表整个进程结束了进程结束所有线程全部退出哪怕没有执行完因此在多线程中主线程应该是最后退出的为什么需要线程等待已经退出的线程其空间没有被释放仍然在进程的地址空间内。创建新的线程不会复⽤刚才退出线程的地址空间2.1 pthread_join1功能pthread_join是 POSIX 线程pthread库中用于等待指定线程终止并回收其资源的函数2函数原型#include pthread.h int pthread_join(pthread_t thread, void **retval);3函数参数thread要等待的线程标识符由pthread_create返回的pthread_t类型retval指向指针的指针用于存储目标线程的返回值如果不关心返回值可以设置为NULL目标线程的返回值通过pthread_exit()或return语句返回4返回值成功返回 0失败返回错误代码不是设置errno5示例// 线程执行入口 void* thread_func(void* args) { std::string str (char*)args; int cnt 5; // 第二个循环 while(cnt--) { printf(New thread:%s\n, str.c_str()); sleep(1); } // 返回一个整数 return (void*)10; } int main() { // 线程名字 const char* name thread-1; pthread_t tid; // 创建线程 int pid pthread_create(tid, nullptr, thread_func, (void*)name); // 主线程 // 等待线程 // 记录退出信息 void* ret nullptr; int n pthread_join(tid, ret); // 不需要考虑线程异常问题因为没机会处理 printf(wait 0x%p succeed, thread exit information:%lld\n, (void*)tid, (long long)ret); return 0; }6应用层面传参和返回值// 模拟一个简单的线程任务类 class Task { public: Task(int x 0, int y 0, int result 0, int exitCode 0) :_x(x) ,_y(y) ,_result(result) ,_exitCode(exitCode) {} void Div() { if(_y 0) { // 出现错误设置错误码 _exitCode 1; return; } _result _x / _y; } void Print() { std::coutresult:_result exitCode:_exitCodestd::endl; } private: int _x; int _y; int _result; int _exitCode; }; // 线程执行入口 void* thread_func(void* args) { // 接收任务类 Task* task (Task*)args; task-Div(); // 返回任务类 return (void*)task; } int main() { // 线程名字 const char* name thread-1; // 创建任务类 Task* task new Task(20, 0); pthread_t tid; // 创建线程,传递任务 int pid pthread_create(tid, nullptr, thread_func, (void*)task); // 主线程 // 等待线程 // 记录退出信息 void* ret nullptr; int n pthread_join(tid, ret); task (Task*)ret; task-Print(); // 不需要考虑线程异常问题因为没机会处理 printf(wait 0x%p succeed, thread exit information:%lld\n, (void*)tid, (long long)ret); return 0; }3 线程终止如果需要只终⽌某个线程⽽不终⽌整个进程,可以有三种⽅法:从线程函数return。这种⽅法对主线程不适⽤,从main函数return相当于调⽤exit线程可以调⽤pthread_ exit终⽌⾃⼰。⼀个线程可以调⽤pthread_ cancel终⽌同⼀进程中的另⼀个线程。3.1 pthread_exit1功能pthread_exit是 POSIX 线程库中用于显式终止调用线程的函数它允许线程在结束执行时返回一个值给其他等待它的线程。2函数原型#include pthread.h void pthread_exit(void *retval);3函数参数retval线程的退出状态值可以被其他线程通过pthread_join获取可以传递任何类型的指针但接收方需要知道如何解析如果不需要返回值可以设为NULL3.2 pthread_cancel1功能pthread_cancel是 POSIX 线程库中用于请求取消终止另一个线程的函数。它提供了一种异步终止线程的机制。2函数原型#include pthread.h int pthread_cancel(pthread_t thread);3函数参数thread要取消的目标线程的标识符由pthread_create返回的pthread_t类型4返回值成功返回 0失败返回错误代码不是设置errno4 线程分离默认情况下新创建的线程是joinable的线程退出后需要对其进⾏pthread_join操作否则⽆法释放资源从⽽造成系统泄漏如果不关心线程的返回值join是⼀种负担这个时候我们可以告诉系统当线程退出时⾃动释放线程资源4.1 pthread_detach1功能pthread_detach是 POSIX 线程库中用于将线程标记为分离状态(detached state)的函数使线程终止时能够自动释放资源无需其他线程调用 pthread_join。2函数原型#include pthread.h int pthread_detach(pthread_t thread);3函数参数thread要设置为分离状态的线程标识符由pthread_create返回的pthread_t类型4返回值成功返回 0失败返回错误代码不是设置errno5示例// 线程执行入口 void* thread_func(void* args) { // 线程主动分离 pthread_detach(pthread_self()); std::string str (char*)args; // 返回 return (void*)10; } int main() { // 线程名字 const char* name thread-1; pthread_t tid; // 创建线程,传递任务 int pid pthread_create(tid, nullptr, thread_func, (void*)name); // 主进程分离指定线程 pthread_detach(tid); sleep(1); // 主线程 // 等待线程 // 记录退出信息 void* ret nullptr; int n pthread_join(tid, ret); // 不需要考虑线程异常问题因为没机会处理 printf(wait 0x%p succeed, thread exit information:%lld, code:%d\n, (void*)tid, (long long)ret, n); return 0; }5 POSIX库与线程有关的函数构成了⼀个完整的系列绝⼤多数函数的名字都是以“pthread_”打头的要使⽤这些函数库要通过引⼊头文件链接这些线程函数库时要使⽤编译器命令的“-lpthread”选项因为头文件 不属于C标准库属于Linux系统的原生库也就是第三方库5.1 线程ID及进程地址空间布局pthread_ create函数会产⽣⼀个线程ID存放在第⼀个参数指向的地址中。该线程ID和前⾯说的线程ID不是⼀回事。前⾯讲的线程ID属于进程调度的范畴。因为线程是轻量级进程是操作系统调度器的最⼩单位所以需要⼀个数值来唯⼀表⽰该线程。pthread_ create函数第⼀个参数指向⼀个虚拟内存单元该内存单元的地址即为新创建线程的线程ID属于NPTL线程库pthread库的范畴。线程库的后续操作就是根据该线程ID来操作线程的。问题thread_t 到底是什么类型呢取决于实现。对于Linux⽬前实现的NPTL实现⽽⾔pthread_t类型的线程ID本质就是⼀个进程地址空间上的⼀个地址。线程库pthread中创建的TCB结构体的起始地址