C++ 线程(std::thread)使用与并发

文章详细介绍了进程和线程的概念,指出进程是资源分配单位,线程是执行调度单位。接着讲解了并发和并行的区别。重点讲述了C++11引入的多线程支持,包括std::thread类,互斥量、条件变量、未来和原子操作等工具,并列举了std::thread的关键成员函数。最后,文章提供了线程管理的示例,如线程阻塞、参数传递和线程ID获取。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录​​​​​​​

进程和线程

并发和并行

C++11 线程

多线程支持库

std::thread 类成员函数

总结

示例


进程和线程

  • 进程:程序(应用程序,可执行文件)一次执行,便开启了一个进程;

进程是 CPU 独立分配资源的单位

  • 线程:进程中的一个实体,被系统独立分配和调度的基本单位

线程是 CPU 可执行调度的最小单位,进程本身并不能获取 CPU 时间,只有它的线程可以。

线程参与操作系统的调度,参与CPU的竞争,得到分配的时间片,获得处理机(CPU)运行。
进程负责获取操作系统分配的资源,如内存。

并发和并行

  • 并发:同一时段内可以交替处理多个操作,强调同一时段内交替发生;

  • 并行:同一时刻内同时处理多个操作,强调同一时刻同时发生。

C++11 线程

多线程支持库

C++ 标准并没有提供对多进程并发的原生支持,所以 C++ 的多进程并发要靠其他 API。

  • <thread>: 提供线程创建及管理的函数或类接口;

  • <mutex>: C++11 互斥量 Mutex。多线程环境下避免竞争同一个公共资源;

  • <condition_variable>: 允许一定量的线程等待(可定时)被另一线程唤醒,然后再继续执行;

  • <future>: 提供了一些工具来获取异步任务(即在单独的线程中启动的函数)的返回值,并捕捉其所抛出的异常;

  • <atomic>: 为细粒度的原子操作(不能被处理器拆分处理的操作)提供组件,允许无锁并发编程。

std::thread 类成员函数

  • get_id: thread::id 线程 ID 获取;

  • joinable: 检查线程是否可被 join 。检查线程是否标识 active 的可行性编程;

    缺省构造的、已完成 join 的、已经 detach 的线程都不是 joinable 。

  • join: 函数关联并阻塞线程,等待该线程执行完毕后继续;

  • detach: 函数解除关联使线程可以和主线程并发执行,若主线程执行完毕退出则关联线程也将自动退出;

  • native_handle: 返回与 std::thread 具体实现相关联的线程句柄;

  • swap: 交换两个线程对象所代表的底层句柄;

  • operator: 移动线程对象。

    命名空间 this_thread 声明在 <thread> 头文件中,可对当前调用者线程的 ID 的获取:

  • get_id: 获取当前调用者线程的ID;

  • yield: 将调用者线程跳出运行状态,重新交给操作系统进行调度,即当前线程放弃执行,操作系统调度另一线程继续执行;

  • sleep_until: 将线程阻塞至某个时间点(time point);

  • sleep_for: 将线程阻塞某个指定时间片(time span),不过由于线程调度等原因,实际休眠可能比 sleep_duration 所表示的更长。

总结

  1. 判断一个 thread 对象是否关联某个线程,使用 joinable() 接口,返回 true 则表明该对象关联着某个线程(即使该线程已经执行结束);

  2. joinable 的对象析构前必须调用 join() 等待结束,或者调用 detach() 解除关联;

  3. 正在执行的线程从关联的对象 detach() 后会自主执行直至结束,对应的对象变成不关联任何线程的对象,joinable() 返回 false;

  4. std::thread 没有拷贝构造和拷贝复制,没有多个对象表示同一执行线程;

  5. 默认构造的、被移动后的、detach 或 join 后的线程对象不关联任何线程。

示例

  • 可调用函数,时间段阻塞(线程暂停)
// 时间段阻塞线程
void f1()
{
    std::cout << "hello" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

    // 调用
    std::thread t1(f);
    t1.join();
  • 函数重载,带参数
// 可调用函数重载,线程带参数
class Task
{
public:
    void operator()(int i)
    {
        std::cout << "参数:" << i << std::endl;
    }
};

    // 调用
    Task task;
    std::thread t3(task, i);
    t3.join();
  • 线程传递引用
void f2(int &i)
{
    std::cout << "引用 :" << (i+=4) << std::endl;
}

    // 调用
    std::thread t4(f2, std::ref(i));
    t4.join();
  • 转移线程所有权
    std::thread t5(std::move(t4));
  • 线程 ID
    // 线程调用函数内部获取
    // function(){std::thread::id this_id = std::this_thread::get_id();}
    // 线程获取
    std::thread::id id = t5.get_id();
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值