早期 C++ 标准库没有提供多线程支持,在 C++ 上使用多线程需要借助 特定操作系统提供的 API,比如 Linux 上的 POSIX 线程库(pthread),Windows 上的 Windows API。它们提供的都是 C 语言的 API,在 C++ 上使用时通常会将其封装成类,顺便在这层封装上解决兼容性问题。C++11 正式将多线程纳入标准库,以面向对象、RAII 方式提供了 std::thread std::mutex 等一系列相关的类。
下面会依次介绍 C++11 之前 Linux 和 Windows 平台上 C 风格的多线程 API,以及 C++11 标准库提供的统一的面向对象的多线程相关类。
Linux pthread 库的多线程 API
Linux 上的 pthread 库实现了 POSIX 线程接口,提供了操作线程和 4 种锁的相关 API,是 Linux 和其他类 UNIX 系统中用于多线程编程的库。
API 清单
#include <pthread.h>
/// 线程,类型是 pthread_t,底层就是一个整型,所以参数 thread 就是一个线程 ID
pthread_create(*thread, *attr, *func) -> int // 创建
pthread_join (thread, void** retval) -> int // 阻塞等待某个线程退出
// 控制线程生命周期的 API
pthread_exit (void* retval) -> void // 线程主动退出,类似 return
pthread_cancel(thread) -> int // 请求停止某个线程
/**
* pthread_cancel 可能导致内存泄漏,因为被取消的线程可能中断正在执行的任务
* 应设计线程良好地响应取消请求
* retval 是返回的错误码,不需要时直接置 NULL
*/
/// 互斥锁,类型是 pthread_mutex_t 结构体
pthread_mutex_init (*mutex, *attr) -> int // 创建
pthread_mutex_destroy(*mutex) -> int // 销毁
ptrehad_mutex_lock (*mutex) -> int // 加锁,阻塞
pthread_mutex_trylock(*mutex) -> int // 加锁,非阻塞
pthread_mutex_unlock (*mutex) -> int // 解锁
/// 条件变量,类型是 pthread_cond_t 结构体
pthread_cond_init (*cond) -> int // 创建
pthread_cond_destroy (*cond) -> int // 销毁
pthread_cond_wait (*cond, *mutex) -> int // 等待某个条件变量,-1 操作
pthread_cond_timewait (*cond, *mutex, time) -> int // 超时等待
pthread_cond_signal (*cond) -> int // 唤醒一个等待该条件变量的线程,随机唤醒,+1 操作
pthread_cond_broadcast(*cond) -> int // 唤醒所有等待该条件变量的线程,+1 操作
/**
* pthread_mutex_t 结构体内部结构依赖于操作系统或库的具体实现,
* 对外部用户而言,它是一个不透明的类型,意味着你不需要知道其内部结构,只需通过提供的API来操作它
* 条件变量需要一个锁来保护,以确保 wait 和 signal 操作的原子性
*/
/// 读写锁,类型是 pthread_rwlock_t 结构体
pthread_rwlock_init (*rwlock, *attr) -> int //
pthread_rwlock_destroy (*rwlock) -> int
pthread_rwlock_rdlock (*rwlock) -> int // 加读锁
pthread_rwlock_tryrdlock(*rwlock) -> int
pthread_rwlock_wrlock (*rwlock) -> int // 加写锁
pthread_rwlock_trywrlock(*rwlock) -> int
pthread_rwlock_unlock (*rwlock) -> int
/**
* 读共享,写独占
*/
/// 自旋锁,类型是 pthread_spinlock_t 结构体
pthread_spin_init (*spinlock, int);
pthread_spin_destroy(*spinlock);
pthread_spin_lock (*spinlock);
pthread_spin_trylock(*spinlock);
pthread_spin_unlock (*spinlock);
demo
一个简单 demo,创建多线程打印线程 ID。
/* MultiThreadExample.cpp */
#include <pthread.h>
#include <stdio.h>
void *threadFunction(void *arg) {
pthread_t tid = pthread_self();
printf("Thread ID: %lu\n", tid);
return NULL;
}
int main() {
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, threadFunction, NULL);
pthread_create(&thread2, NULL, threadFunction, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
pthread 库是第三方提供,非标准库内置。所以源码用了它,则链接时需要手动链接上 pthread 库。
命令行编译的话,
g++ MultiThreadExample.cpp -lpthread -o MultiThreadExample
如果使用 CMake,则:
add_executable(MultiThreadExample MultiThreadExample.cpp)
# 链接pthreads库
find_package(Threads REQUIRED)
target_link_libraries(MultiThreadExample ${CMAKE_THREAD_LIBS_INIT})
或者直接写出库名,下面的方式和上面方式等价:
add_executable(MultiThreadExample MultiThreadExample.cpp)
# 链接pthreads库
target_link_libraries(MultiThreadExample pthread)
Windows API 提供的多线程 API
API 清单
#include <windows.h>
/// 线程
CreateThread() -> HANDLE
ExitThread()
CloseHandle()
GetCurrentThread() // 获取当前线程的句柄
GetCurrentThreadId() // 获取当前线程的 ID
/// 互斥锁
CreateMutex()
ReleaseMutex()
OpenMutex()
/// 条件变量
/// 读写锁
/// 自旋锁
/// 事件机制
CreateEvent()
SetEvent()
ResetEvent()
WaitForSingleObject()
WaitForMultipleObject()
C++11 标准库提供的线程库 Thread
自C++11标准起,多线程编程正式成为C++语言的一部分。标准库新增了 <thread>、<mutex>、<atomic>、<future> 等头文件,为开发者提供了统一、高效且易于使用的多线程编程工具集。
API
/// 线程,std::thread 类
#include <thread>
std::thread::thread(func, args...) // 构造函数,创建并启动一个线程
std::thread::join()
std::thread::detach()
/// 互斥锁,std::mutex 类
#include <mutex>
std::mutex
std::lock_guard // RAII 类,自动管理锁的生命周期
std::unique_lock
/// 条件变量,std::condition_variable 类
#include <condition_variable>
std::condition_variable
std::recursive_mutex
/// 原子类型,std::atomic 类
#include <atomic>
demo
用 C++11 的 API 复现之前的 demo
#include <iostream>
#include <thread>
#include <string>
// 线程执行的函数
void print_thread_id(const std::string& thread_name) {
std::cout << thread_name << " Thread ID: " << std::this_thread::get_id() << std::endl;
}
int main() {
// 创建并启动两个线程
std::thread thread1(print_thread_id, "Thread 1");
std::thread thread2(print_thread_id, "Thread 2");
// 等待两个线程完成
thread1.join();
thread2.join();
std::cout << "Both threads have finished execution." << std::endl;
return 0;
}
注意,编译时依然要显式链接上 pthread 库,因为 C++11 的 std::thread 本质上就是对操作系统提供的多线程 API 做了封装,所以在 Linux 上依然依赖 pthread 库。
add_executable(MultiThreadExample_C11 MultiThreadExample_C11.cpp)
target_link_libraries(MultiThreadExample_C11 pthread)