前言
POSIX 线程(Pthreads) 是一种在 POSIX 标准下定义的线程库,它为多线程编程提供了统一的接口,主要用于 UNIX 和类 UNIX 系统(如 Linux、MacOS 和 BSD 等)。POSIX 线程允许程序在多个处理器上并行运行,从而提高应用程序的性能,尤其在多核处理器环境中。
POSIX 线程库为 UNIX 类系统提供统一的多线程编程接口。文章详解了 pthread_create 创建线程、pthread_join 等待线程结束、pthread_exit 显式退出、pthread_cancel 发送取消请求及 pthread_detach 设置分离状态。通过 C++ 示例代码演示了主线程与子线程的并发执行、同步机制及资源回收流程,涵盖线程属性配置、返回值传递及异常处理,帮助开发者掌握 Linux 下多线程的核心控制逻辑。

POSIX 线程(Pthreads) 是一种在 POSIX 标准下定义的线程库,它为多线程编程提供了统一的接口,主要用于 UNIX 和类 UNIX 系统(如 Linux、MacOS 和 BSD 等)。POSIX 线程允许程序在多个处理器上并行运行,从而提高应用程序的性能,尤其在多核处理器环境中。

while :; do ps -aL | head -1; ps -aL | grep thread ; sleep 1; done
pthread_ 打头的pthread.h-lpthread 选项pthread_create)
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
**pthread_t *thread**:指向 pthread_t 类型的变量,这个变量将存储新线程的 ID。**const pthread_attr_t *attr**:指向 pthread_attr_t 类型的指针,它包含了新线程的属性(如栈大小、调度策略等)。如果传入 NULL,则使用默认属性。**void *(*start_routine)(void *)**:这是一个指向线程执行函数的指针,该函数接收一个 void* 类型的参数,并返回 void* 类型的结果。**void *arg**:这是传递给 start_routine 函数的参数,允许你向线程传递数据。#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;
// 线程函数
void* mythread(void* args) {
// 创建一个循环,子线程会打印 6 次
for (int i = 0; i < 6; i++) {
sleep(1); // 让线程睡眠 1 秒钟,模拟任务的执行
cout << "Child Thread" << endl; // 打印'Child Thread',表示子线程在运行
}
return nullptr;
}
// 主函数
int main() {
pthread_t tid; // 定义一个线程 ID 变量
// 创建子线程,线程的执行函数是 mythread,其他参数为默认值
pthread_create(&tid, nullptr, mythread, nullptr);
// 主线程执行,循环 6 次
for (int i = 0; i < 6; i++) {
cout << "Main Thread" << endl; // 打印'Main Thread',表示主线程在运行
sleep(1); // 让主线程睡眠 1 秒钟
}
// 等待子线程完成执行
pthread_join(tid, nullptr); // 阻塞等待 tid 线程执行完毕
return 0; // 程序正常退出
}
**pthread_create()**:用于创建一个新的线程,mythread 是新线程的执行函数。该函数接受参数 nullptr,表示没有传递任何参数给线程。**pthread_join(tid, nullptr)**:等待线程 tid 执行完成,pthread_join 阻塞主线程,直到子线程执行完毕。打印结果:

pthread_join
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
pthread_t thread:要等待结束的线程 ID。**void **retval**:用于存储线程返回值的指针。如果不需要返回值,可以将其设置为 NULL。pthread_join() 函数使得调用该函数的线程(通常是主线程)阻塞,直到指定的线程(由 thread 参数指定)执行完毕。retval 不为 NULL,线程的返回值将被存储在 retval 指向的位置。#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;
// 子线程的执行函数
void* mythread(void* args) {
// 循环 6 次,每次打印一次信息,并且每次暂停 1 秒
for (int i = 0; i < 6; i++) {
sleep(1); // 休眠 1 秒钟
cout << "Child Thread is running ...." << endl; // 输出子线程运行的提示
}
// 返回一个值 100,并强制转换为 void* 类型
return (void*)100;
}
int main() {
pthread_t tid; // 定义一个线程 ID 变量
// 创建子线程,传入 mythread 函数作为线程执行的函数,参数为 nullptr
pthread_create(&tid, nullptr, mythread, nullptr);
// 主线程运行 6 次,每次输出一次信息,并且每次暂停 1 秒
for (int i = 0; i < 6; i++) {
cout << "Main Thread is running .." << endl; // 输出主线程运行的提示
sleep(1); // 休眠 1 秒钟
}
void* retval; // 声明一个指向 void 的指针,用于接收子线程的返回值
// 等待子线程结束,并将子线程的返回值存储到 retval 中
pthread_join(tid, &retval);
// 输出子线程的返回值,将其强制转换为整数类型并输出
cout << (int64_t)retval << endl; // 输出子线程的返回值,转换为整数
return 0;
}
pthread_join() 等待子线程完成,并获取子线程的返回值。return (void*)100 返回一个 void* 类型的值,主线程通过 pthread_join() 捕获该返回值并输出。打印:

pthread_exit
#include <pthread.h>
void pthread_exit(void* retval);
retval:这是一个指针,线程退出时可以返回的值。该值可以被其他线程通过 pthread_join 获取,用来传递线程的退出状态或其他信息。retval 可以是任何类型的指针,通常是一个线程退出的状态信息。#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;
void* mythread(void* args) { // 线程函数
// 子线程执行的操作,循环输出 "Child Thread is running ...."
for (int i = 0; i < 6; i++) {
sleep(1); // 每次休眠 1 秒
cout << "Child Thread is running ...." << endl;
}
// 输出结束前的信息
cout << "Child Pthread_exit" << endl;
// 使用 pthread_exit 显式退出线程并返回一个状态码 100
pthread_exit((void*)100);
// 这一行代码不会被执行到,因为 pthread_exit 已经退出线程
return (void*)100;
}
int main() {
pthread_t tid; // 声明一个线程标识符
// 创建线程
pthread_create(&tid, nullptr, mythread, nullptr);
// 主线程执行的操作
for (int i = 0; i < 6; i++) {
cout << "Main Thread is running .." << endl;
sleep(1); // 每次休眠 1 秒
}
// 主线程休眠,确保子线程有时间执行
sleep(8); // 等待子线程执行完毕
// 主线程结束前输出信息
cout << "main return " << endl;
return 0; // 程序结束
}
sleep(8) 来等待子线程的执行。此时,子线程已经执行完它的循环,并通过 pthread_exit 显式退出。pthread_join(),主线程并没有等待子线程完成,它只是通过 sleep(8) 暂停一段时间,确保子线程有足够的时间结束。打印:

pthread_cancel
#include <pthread.h>
int pthread_cancel(pthread_t thread);
pthread_t thread:目标线程的线程 ID(TID),即你希望取消的线程。pthread_cancel 用于向指定的线程发送取消请求。调用此函数后,目标线程会接收到取消请求,并在合适的时机响应取消请求。#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <vector>
#include <string>
using namespace std;
// Hex 函数,用于将整数转换为十六进制字符串
string Hex(int data) {
char buff[1034] = {0};
// snprintf 用于将整数 data 转换为十六进制字符串
snprintf(buff, sizeof(buff), "0x%x", data);
return buff;
}
// 线程函数,打印每个线程的整数值
void* mythread(void* args) {
// 将传入的参数指针转换为整型指针
int* i = (int*)args;
while (true) { // 无限循环,模拟线程的持续运行
sleep(1); // 每次休眠 1 秒
cout << "thread: " << *i << endl; // 输出线程 ID(即传递给线程的值)
}
return (void*)100; // 返回一个指针类型的值,通常线程退出时返回状态
}
int main() {
// 定义一个 vector 来存储线程 ID
vector<pthread_t> th;
// 创建 4 个线程
for (int i = 0; i < 4; i++) {
pthread_t tid; // 定义一个线程 ID 变量
// 创建线程,将线程 ID、线程函数(mythread)以及传递给线程的参数(i 的地址)传入
pthread_create(&tid, nullptr, mythread, &i);
// 将线程 ID 添加到线程容器中
th.push_back(tid);
}
cout << "ready cancel" << endl;
sleep(3); // 休眠 3 秒,等待线程输出
// 取消每个创建的线程
for (int i = 0; i < th.size(); i++) {
cout << "cancel: thread " << i << endl; // 输出正在取消的线程编号
pthread_cancel(th[i]); // 取消对应的线程
}
sleep(1); // 稍等 1 秒,确保线程能够响应取消请求
cout << "main return " << endl; // 输出主线程返回信息
return 0; // 程序结束
}
pthread_create() 创建 4 个子线程,每个子线程打印传递给它的整数值(即循环中的 i),并在每秒打印一次。thread: <value>,其中 <value> 是它收到的整数(传递给线程的 i)。pthread_cancel() 来取消所有 4 个线程,每个线程被取消后,它会终止执行(线程的退出取决于它们在什么地方被取消)。"main return" 并结束,程序执行完毕。打印:


#include <pthread.h>
int pthread_detach(pthread_t thread);
thread:要设置为分离状态的线程 ID。pthread_detach 用于将一个线程设置为 分离状态。当线程被设置为分离状态后,线程在完成执行时会自动释放资源,而不需要其他线程显式地调用 pthread_join() 来清理线程资源。#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <vector>
#include <string>
using namespace std;
// Hex 函数:将整数转换为十六进制字符串
string Hex(int data) {
char buff[1034] = {0};
snprintf(buff, sizeof(buff), "0x%x", data); // 将整数以十六进制格式转换成字符串
return buff;
}
// 线程函数
void* mythread(void* args) {
pthread_detach(pthread_self()); // 将当前线程设置为分离状态
int* i = (int*)args; // 将传入的参数指针转换为整型指针
int n = 3; // 循环打印线程编号(传递给线程的值),共打印 3 次
while (n--) {
sleep(1); // 每次循环休眠 1 秒
cout << "thread: " << *i << endl; // 输出线程的编号
}
return (void*)100; // 线程返回值
}
int main() {
vector<pthread_t> th; // 用于存储线程 ID 的容器
cout << "线程的创建" << endl;
// 创建 4 个线程
for (int i = 0; i < 4; i++) {
pthread_t tid;
pthread_create(&tid, nullptr, mythread, &i); // 创建线程并传递 i 的地址作为参数
th.push_back(tid); // 将创建的线程 ID 加入到线程容器中
}
sleep(10); // 主线程休眠 10 秒,确保所有子线程能运行完
cout << "main return " << endl;
return 0; // 主程序结束
}
pthread_create 创建 4 个子线程,每个子线程都会执行 mythread 函数。pthread_detach)。打印:


微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
暂无推荐文章,稍后可再来查看。
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online