thread 基础与线程管理
定义与作用
std::thread 是 C++11 引入的标准线程类,封装操作系统原生线程,提供统一的跨平台线程管理接口。
#include <thread>
std::thread t([]() { std::cout << "Hello from thread\n"; });
t.join(); // 等待线程结束
核心原理
线程生命周期
join vs detach
完整示例
示例一:飞翔科技并行日志分析
场景说明:李眉用多线程并行分析多个服务器日志文件。
#include <iostream>
#include <thread>
#include <vector>
#include <string>
#include <chrono>
#include <sstream>
#include <iomanip>
// 模拟单台服务器的日志分析
struct AnalysisResult {
std::string serverName;
int totalLines = 0;
int errorCount = 0;
int warnCount = 0;
double avgCpu = 0.0;
int duration_ms = 0;
};
AnalysisResult analyzeServerLog(const std::string& serverName,
int lineCount) {
auto start = std::chrono::steady_clock::now();
auto tid = std::this_thread::get_id();
// 模拟耗时分析
int errors = 0, warns = 0;
for (int i = 0; i < lineCount; ++i) {
// 模拟 CPU 密集型工作
volatile int x = 0;
for (int j = 0; j < 1000; ++j) x += j;
if (i % 100 == 0) ++errors;
if (i % 50 == 0) ++warns;
}
auto end = std::chrono::steady_clock::now();
int ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
std::ostringstream oss;
oss << " [线程 " << tid << "] " << serverName << " 分析完成 ("
<< ms << "ms)\n";
// 加锁输出避免交错(仅为演示)
static std::mutex coutMutex;
{
std::lock_guard<std::mutex> lock(coutMutex);
std::cout << oss.str() << std::flush;
}
return {serverName, lineCount, errors, warns, 0.0, ms};
}
int main() {
std::cout << "=== 飞翔科技并行日志分析 ===\n";
std::cout << "CPU 逻辑核心数: " << std::thread::hardware_concurrency() << "\n\n";
std::vector<std::thread> threads;
std::vector<AnalysisResult> results;
// 使用 mutex 保护 results
std::mutex resultMutex;
auto startAll = std::chrono::steady_clock::now();
// 启动多个线程分析不同服务器
std::vector<std::pair<std::string, int>> servers = {
{"Web-01", 5000},
{"Web-02", 3000},
{"DB-Master",8000},
{"Cache-01", 2000},
{"MQ-01", 4000},
{"Log-01", 6000},
};
for (const auto& [name, lines] : servers) {
threads.emplace_back([&results, &resultMutex, name, lines]() {
auto r = analyzeServerLog(name, lines);
{
std::lock_guard<std::mutex> lock(resultMutex);
results.push_back(r);
}
});
}
std::cout << "已启动 " << threads.size() << " 个线程\n";
// join 所有线程
for (auto& t : threads) {
if (t.joinable()) t.join();
}
auto endAll = std::chrono::steady_clock::now();
int totalMs = std::chrono::duration_cast<std::chrono::milliseconds>(endAll - startAll).count();
std::cout << "\n=== 分析结果 ===\n";
std::cout << std::left
<< std::setw(14) << "服务器"
<< std::setw(10) << "日志行数"
<< std::setw(10) << "错误数"
<< std::setw(10) << "警告数"
<< std::setw(10) << "耗时(ms)"
<< "\n";
std::cout << std::string(54, '-') << "\n";
int totalLines = 0, totalErrors = 0, totalWarns = 0;
for (const auto& r : results) {
std::cout << std::left
<< std::setw(14) << r.serverName
<< std::setw(10) << r.totalLines
<< std::setw(10) << r.errorCount
<< std::setw(10) << r.warnCount
<< std::setw(10) << r.duration_ms
<< "\n";
totalLines += r.totalLines;
totalErrors += r.errorCount;
totalWarns += r.warnCount;
}
std::cout << std::string(54, '-') << "\n";
std::cout << std::left
<< std::setw(14) << "合计"
<< std::setw(10) << totalLines
<< std::setw(10) << totalErrors
<< std::setw(10) << totalWarns
<< "\n";
std::cout << "\n总耗时: " << totalMs << "ms\n";
std::cout << "并行效率: 使用 " << threads.size()
<< " 个核心处理 " << totalLines
<< " 行日志\n";
}
预期输出:
=== 飞翔科技并行日志分析 ===
CPU 逻辑核心数: 16
已启动 6 个线程
[线程 12345] Web-01 分析完成 (XXXms)
[线程 12346] Web-02 分析完成 (XXXms)
...
=== 分析结果 ===
服务器 日志行数 错误数 警告数 耗时(ms)
------------------------------------------------------
Web-01 5000 50 100 XXX
Web-02 3000 30 60 XXX
...
总耗时: XXXms
并行效率: 使用 6 个核心处理 28000 行日志
逐段分析:
std::thread构造时立即启动线程执行可调用对象hardware_concurrency()返回逻辑核心数,用于确定并行度- 必须
join()或detach(),否则析构时std::terminate std::mutex+lock_guard保护共享results容器this_thread::get_id()获取当前线程 ID
示例二:detach 与后台线程
场景说明:大翔让飞翔科技的监控线程在后台持续运行。
#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>
std::atomic<bool> running{true};
void backgroundMonitor() {
std::cout << "[监控] 后台线程启动\n";
int tick = 0;
while (running.load(std::memory_order_relaxed)) {
std::this_thread::sleep_for(std::chrono::seconds(1));
++tick;
// 模拟指标采集
if (tick % 5 == 0)
std::cout << "[监控] 心跳 #" << tick << " - 系统正常\n";
}
std::cout << "[监控] 收到停止信号,安全退出 (共运行 "
<< tick << " 秒)\n";
}
int main() {
std::cout << "=== 飞翔科技后台监控 ===\n\n";
// 启动后台线程并 detach
std::thread monitor(backgroundMonitor);
monitor.detach(); // 分离——线程独立运行
std::cout << "监控线程已分离,主线程继续...\n\n";
// 主线程执行其他任务
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout << "[主线程] 处理业务请求...\n";
std::this_thread::sleep_for(std::chrono::seconds(3));
// 发送停止信号
std::cout << "\n[主线程] 发送停止信号\n";
running.store(false, std::memory_order_relaxed);
// 给 detach 线程一些时间退出
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "[主线程] 程序结束\n";
}
预期输出:
=== 飞翔科技后台监控 ===
[监控] 后台线程启动
监控线程已分离,主线程继续...
[监控] 心跳 #5 - 系统正常
[监控] 心跳 #10 - 系统正常
[主线程] 处理业务请求...
[监控] 心跳 #15 - 系统正常
[主线程] 发送停止信号
[监控] 收到停止信号,安全退出 (共运行 17 秒)
[主线程] 程序结束
逐段分析:
detach()后线程独立运行,thread对象不再管理它std::atomic<bool>用于线程间安全通信sleep_for模拟定时任务- detach 线程必须在主线程结束前收到停止信号并自行退出
易错场景与面试考点
易错场景
1. 忘记 join 或 detach
void bad() {
std::thread t([]() { std::cout << "work\n"; });
// t 析构时 joinable() == true → std::terminate()!
}
2. detach 后访问已销毁对象
void bad() {
int local = 42;
std::thread t([&local]() {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << local; // ❌ local 可能已销毁
});
t.detach();
} // local 销毁,detach 线程还在运行
3. 异常导致未 join
void risky() {
std::thread t(work);
doSomethingThatMayThrow(); // 如果抛异常...
t.join(); // ❌ 永远不会执行
}
// 解决:使用 RAII 包装器或 try-catch
面试考点
| 考点 | 要点 |
|---|---|
| thread 构造 | 传函数对象 + 参数,立即启动 |
| join vs detach | join 阻塞等待;detach 分离独立运行 |
| joinable() | 检查线程是否可 join/detach |
| hardware_concurrency | 获取逻辑 CPU 核心数,用于并行度决策 |
| 线程生命周期 | 构造→可join→join/detach→不可join |
| this_thread 命名空间 | get_id(), sleep_for(), sleep_until(), yield() |
| 线程 ID | std:🧵:id 类型,可比较、可哈希、可输出 |
| 异常安全 | 使用 RAII 包装(如 std::jthread C++20) |