3. 跨平台线程API:POSIX Threads (pthreads) 与 C++11 std::thread 的对比、Windows Thread API 与 pthreads 的异同

聊到跨平台多线程,有个问题绕不开:不同操作系统下的线程API,到底怎么统一?

我早年做嵌入式Linux开发时,天天跟pthreads打交道。后来转到Windows平台,第一反应是“这API怎么长得完全不一样?”再后来C++11出了std::thread,我才算松了口气。今天咱们就把这三者掰开揉碎,讲清楚它们的异同。

3.1 POSIX Threads (pthreads) 概览

pthreads是POSIX标准定义的线程接口,在Linux、macOS、FreeBSD等类Unix系统上原生支持。它是一套C语言的API,功能非常完整。

核心特点:

  • 线程创建、退出、等待(join/detach)
  • 互斥锁(mutex)、条件变量(condition variable)、读写锁(rwlock)
  • 信号量(semaphore)、屏障(barrier)
  • 线程局部存储(TLS)

举个例子,创建一个线程并等待它结束:

#include <pthread.h>
#include <stdio.h>

void* thread_func(void* arg) {
    printf("Hello from thread!\n");
    return NULL;
}

int main() {
    pthread_t tid;
    pthread_create(&tid, NULL, thread_func, NULL);
    pthread_join(tid, NULL);
    return 0;
}

嗯,这里要注意:pthread_create的第三个参数是函数指针,返回值必须是void*。我刚开始写的时候老忘记这个签名,编译报错半天找不出原因。

3.2 C++11 std::thread 的封装

C++11标准库引入了std::thread,它本质上是对底层线程API(pthreads或Windows Thread)的C++封装。说白了,它让你用更现代、更安全的方式写多线程代码。

个人习惯:新项目我基本都用std::thread,除非需要pthreads特有的功能(比如设置线程调度策略)。

同样的功能,用std::thread写出来是这样的:

#include <thread>
#include <iostream>

void thread_func() {
    std::cout << "Hello from thread!\n";
}

int main() {
    std::thread t(thread_func);
    t.join();
    return 0;
}

你想想看,代码是不是简洁多了?不需要手动管理pthread_t,不需要担心返回值类型,还支持lambda表达式:

std::thread t([](){
    std::cout << "Lambda thread!\n";
});
t.join();

3.3 Windows Thread API 与 pthreads 的异同

Windows有自己的线程API,叫CreateThread。它跟pthreads的设计哲学完全不同。

功能 pthreads Windows Thread API
创建线程 pthread_create CreateThread
等待线程 pthread_join WaitForSingleObject
退出线程 pthread_exit / return ExitThread / return
互斥锁 pthread_mutex_t CRITICAL_SECTION / Mutex
条件变量 pthread_cond_t ConditionVariable (Vista+)
线程局部存储 __thread / pthread_key_t __declspec(thread) / TlsAlloc

我曾在项目中遇到一个坑:Windows的CreateThread返回的是HANDLE,而pthread_create返回的是pthread_t。HANDLE需要手动CloseHandle,否则会泄漏内核对象。pthread_t则不需要。这个差异让我在移植代码时吃了不少苦头。

避坑指南:我曾经在Windows上用CreateThread创建线程后忘记CloseHandle,导致程序运行一段时间后线程数暴涨,最终系统资源耗尽。后来改用_beginthreadex(C运行时库版本)才解决了问题。

3.4 跨平台封装策略

既然不同平台的API差异这么大,怎么实现跨平台呢?我总结了几种常见做法:

  • 条件编译:用#ifdef _WIN32 / #ifdef __linux__ 分别调用不同API。适合小项目。
  • 抽象层封装:自己写一个Thread类,内部用pthreads或Windows API实现。C++11之前很多库这么干。
  • 直接使用std::thread:C++11标准库已经帮你封装好了,跨平台无痛。除非你还在用老编译器。

我个人推荐第三种。你想想看,既然标准库已经帮你解决了跨平台问题,何必自己再折腾一遍?

3.5 性能对比与选择建议

性能上,pthreads和Windows Thread API都是原生实现,std::thread是薄封装,开销几乎可以忽略。但有几个细节要注意:

  • pthreads的互斥锁默认是普通锁,不支持递归。Windows的CRITICAL_SECTION默认支持递归。
  • Windows的条件变量从Vista才开始原生支持,XP上需要自己模拟。
  • pthreads支持设置线程的调度策略(SCHED_FIFO、SCHED_RR),Windows没有直接对应。

我的建议:桌面应用用std::thread就够了。嵌入式实时系统如果需要对线程调度精细控制,还是得用pthreads。

3.6 知识体系结构图

下面这张图展示了本章的核心逻辑:三种线程API的关系与适用场景。

跨平台线程API知识体系 POSIX Threads C++11 std::thread Windows Thread API 特性 • 原生C API • 功能最完整 • 精细调度控制 • Linux/macOS原生 特性 • C++封装 • 跨平台无痛 • 支持lambda • 现代C++推荐 特性 • HANDLE管理 • 递归锁默认 • 需CloseHandle • Windows原生 选择建议:桌面应用用std::thread,实时系统用pthreads,Windows专用用原生API

这张图把三者的定位和特性梳理清楚了。你写代码时,根据项目需求对号入座就行。

3.7 实际项目中的选择

最后说说我的实际经验。如果你在做一个跨平台的开源库,比如网络库、数据库驱动,我建议底层用pthreads(Windows上用pthreads-w32移植版),上层暴露std::thread兼容的接口。这样既保证了性能,又方便用户使用。

如果你只是写一个内部工具,团队统一用C++17,那就直接用std::thread。省心,少出bug。

一句话总结:pthreads是底层基石,std::thread是上层封装,Windows API是另一套体系。理解它们的异同,你就能写出真正跨平台的多线程代码。

可可精品资料库