c++多线程(1)------创建和管理线程td::thread

发布于:2025-09-05 ⋅ 阅读:(19) ⋅ 点赞:(0)
  • 操作系统:ubuntu22.04
  • IDE:Visual Studio Code
  • 编程语言:C++11

算法描述

std::thread 是 C++11 标准库中用于创建和管理线程的核心类,定义在 头文件中。它使得多线程编程变得简单、类型安全且跨平台。

一、std::thread 简介

std::thread 是一个类,代表一个执行线程。你可以用它来启动一个函数(普通函数、lambda、函数对象、成员函数等)在新的线程中运行。
🔧 所需头文件:

#include <thread>

📦 常用成员函数:

函数 说明
join() 等待线程执行完毕(阻塞主线程)
detach() 分离线程,让其在后台独立运行
get_id() 获取线程的唯一 ID
joinable() 判断线程是否可以 join 或 detach
swap() 交换两个 thread 对象
native_handle() 获取底层平台的原生线程句柄(如 pthread_t)

二、创建线程的多种方式(附示例)

  1. 使用普通函数
#include <iostream>
#include <thread>
#include <chrono>

void hello() 
{
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::cout << "Hello from thread " << std::this_thread::get_id() << std::endl;
}

int main()
{
    std::thread t(hello);  // 启动线程执行 hello 函数

    std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;

    t.join();  // 等待线程结束

    std::cout << "Thread joined." << std::endl;
    return 0;
}

输出示例:

Main thread ID: 1
Hello from thread 2
Thread joined.
  1. 使用带参数的函数
void print_message(const std::string& msg, int n) 
{
    for (int i = 0; i < n; ++i) 
    {
        std::cout << msg << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
    }
}

int main()
{
    std::thread t(print_message, "Hello from thread!", 3);

    std::cout << "Main thread is running..." << std::endl;

    t.join();

    std::cout << "Thread finished." << std::endl;
    return 0;
}
⚠️ 注意:参数是值传递的。如果要传引用,必须用 std::ref。

✅ 正确传递引用:

void increment(int& x)
{
    ++x;
}

int main() 
{
    int a = 0;
    std::thread t(increment, std::ref(a));  // 使用 std::ref 传引用
    t.join();
    std::cout << "a = " << a << std::endl;  // 输出: a = 1
    return 0;
}

✅ 3. 使用 Lambda 表达式

int main()
{
    int local = 10;

    std::thread t([local]()
    {  
        // 捕获 local 的副本
        std::cout << "Lambda: local = " << local << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    });

    t.join();
    return 0;
}
提示:如果要修改捕获的变量,使用 mutable 或传引用:
std::thread t([&local]() mutable 
{
    local += 5;
    std::cout << "Modified: " << local << std::endl;
});

✅ 4. 使用函数对象(仿函数)

struct Task 
{
    void operator()() const
    {
        std::cout << "Task executed in thread " << std::this_thread::get_id() << std::endl;
    }
};

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

✅ 5. 使用类的成员函数

class Worker 
{
public:
    void work(int id)
     {
        std::cout << "Worker " << id << " working in thread " << std::this_thread::get_id() << std::endl;
    }
};

int main() 
{
    Worker w;
    std::thread t(&Worker::work, &w, 42);  // &w 是对象指针,42 是参数
    t.join();
    return 0;
}

🔍 解释:&Worker::work 是成员函数指针,&w 是对象地址,42 是参数。

三、join() vs detach()

❗ 每个 std::thread 对象在析构前必须被 join 或 detach,否则程序会 std::terminate()。
✅ join():等待线程结束

std::thread t(some_function);
t.join();  // 主线程阻塞,直到 t 结束
// 此时 t 不再可 join,t.joinable() 返回 false

✅ detach():分离线程

std::thread t(some_function);
t.detach();  // 线程在后台运行,不再与 thread 对象关联
// 不能再 join,线程生命周期由系统管理
⚠️ 分离线程的风险:如果主线程结束,整个程序终止,分离线程也会被强制终止。

🧪 四、检查线程状态:joinable()

std::thread t(some_function);

if (t.joinable()) 
{
    t.join();  // 安全调用
}
常用于异常安全代码中,确保线程被正确处理。

🧰 五、线程 ID 与当前线程操作

#include <iostream>
#include <thread>

void show_id() 
{
    std::cout << "This thread ID: " << std::this_thread::get_id() << std::endl;
}

int main() 
{
    std::thread t(show_id);
    std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;

    t.join();

    // 让出 CPU 时间片
    std::this_thread::yield();

    // 休眠 500 毫秒
    std::this_thread::sleep_for(std::chrono::milliseconds(500));

    return 0;
}

🧱 六、线程安全与共享数据(简单示例)

#include <iostream>
#include <thread>
#include <mutex>

int counter = 0;
std::mutex mtx;

void increment() 
{
    for (int i = 0; i < 100000; ++i) 
    {
        std::lock_guard<std::mutex> lock(mtx);
        ++counter;
    }
}

int main() 
{
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "Final counter: " << counter << std::endl;  // 应为 200000
    return 0;
}
🔐 使用 std::mutex 和 std::lock_guard 保护共享变量 counter。

🚫 七、常见错误与注意事项

❌ 错误1:未调用 join 或 detach

int main()
{
    std::thread t([]{ std::cout << "Hello"; });
    return 0;  // t 析构时未 join/detach → 调用 std::terminate()
}

✅ 正确做法:

std::thread t(...);
// ...
t.join();  // 或 t.detach();

❌ 错误2:传递指针或引用时对象已销毁

std::thread t(increment, std::ref(local_var));
// 如果 local_var 是局部变量且线程未结束,可能访问已销毁内存
✅ 建议:确保线程使用的数据生命周期长于线程本身。

✅ 八、完整示例:多线程并行计算

#include <iostream>
#include <vector>
#include <thread>
#include <numeric>

void accumulate(const std::vector<int>& vec, int start, int end, int& result)
 {
    result = std::accumulate(vec.begin() + start, vec.begin() + end, 0);
}

int main() 
{
    std::vector<int> data(100000, 1);  // 10万个1
    int sum1 = 0, sum2 = 0;

    std::thread t1(accumulate, std::ref(data), 0, 50000, std::ref(sum1));
    std::thread t2(accumulate, std::ref(data), 50000, 100000, std::ref(sum2));

    t1.join();
    t2.join();

    std::cout << "Total sum: " << sum1 + sum2 << std::endl;  // 100000
    return 0;
}

总结:std::thread 核心要点

要点 说明
✅ 启动线程 std::thread t(func, args…)
✅ 等待结束 t.join()
✅ 后台运行 t.detach()
✅ 安全检查 t.joinable()
✅ 线程ID t.get_id() 或 std::this_thread::get_id()
✅ 传引用 使用 std::ref()
✅ 异常安全 在异常路径中也要 join/detach

掌握 std::thread 是学习 C++ 多线程的第一步。结合 mutex、condition_variable 和 future,你就能构建出高效、安全的并发程序。建议多写小例子练习传参、生命周期管理、同步等关键点。


网站公告

今日签到

点亮在社区的每一天
去签到