• C++多线程入门


    我们先从一个最简单的例子入手:

    1. #include
    2. #include
    3. #include
    4. void sleep() {
    5. // sleep for 2 seconds
    6. std::this_thread::sleep_for(std::chrono::seconds(2));
    7. }
    8. int main() {
    9. auto startTime = std::chrono::high_resolution_clock::now();
    10. sleep(); // 2s
    11. sleep(); // 2s
    12. auto stopTime = std::chrono::high_resolution_clock::now();
    13. auto duration = std::chrono::duration_cast(stopTime - startTime);
    14. std::cout << "Duration: " << duration.count() / 1e6 << "s" << std::endl;
    15. }

    上述代码的运行时长应该是4s左右,这也符合串行编程的一贯逻辑,即执行完一段代码后再执行下一段代码。但是在许多应用中,串行编程会严重影响程序的执行效率,所以从c++11后引入的thread能让我们较快地上手并行编程,也就是多线程编程

    这里先简单介绍一下线程的优势,线程和进程都是操作系统对资源调度的一种抽象,我们可以将线程视作一种轻量级的进程,一个进程中可以包含多个线程,而这些线程共享进程中的全部资源,比如堆栈、代码、全剧数据等等。而线程仅有较少的私有资源,比如线程的调用栈等。因此,我们说线程是一个轻量级的进程。

    我们对上面的代码进行修改使其可以多线程地调度:

    1. // ...
    2. int main() {
    3. auto startTime = std::chrono::high_resolution_clock::now();
    4. std::thread t1(sleep);
    5. std::thread t2(sleep);
    6. t1.join(); // 阻塞主线程,直至线程t1运行结束
    7. t2.join(); // 阻塞主线程,直至线程t2运行结束
    8. auto stopTime = std::chrono::high_resolution_clock::now();
    9. auto duration = std::chrono::duration_cast(stopTime - startTime);
    10. std::cout << "Duration: " << duration.count() / 1e6 << "s" << std::endl;
    11. }

    修改后,程序运行时间减少为2s。

    1 创建一个线程

    函数指针

    1. void countdown(int x) {
    2. while (x --> 0) std::cout << x << std::endl;
    3. }
    4. int main() {
    5. std::thread t(countdown, 10); // 使用函数指针创建线程
    6. }
    7. Lambda函数:int main() {
    8. std::thread t([] (int x) {
    9. while (x --> 0) std::cout << x << std::endl;
    10. }, 10); // 使用Lambda函数创建线程
    11. }

    函数对象(Functor,Function Object):

    1. class Base {
    2. public:
    3. void operator() (int x) {
    4. while (x --> 0) std::cout << x << std::endl;
    5. }
    6. };
    7. int main() {
    8. std::thread t(Base(), 10); // 使用函数对象指针创建线程
    9. }

    成员函数:

    1. class Base {
    2. public:
    3. void run(int x) {
    4. while (x --> 0) std::cout << x << std::endl;
    5. }
    6. static void static_run(int x) {
    7. while (x --> 0) std::cout << x << std::endl;
    8. }
    9. };
    10. int main() {
    11. Base b;
    12. std::thread t1(&Base::run, &b, 10); // 使用成员函数(非静态)指针创建线程,需要传入对象指针(&b)
    13. std::thread t2(&Base::static_run, 10); // 使用静态成员函数指针创建线程,不需要传入对象指针
    14. }

    2 Join和Detach

    thread.join()的含义是等待(类似js中的await)该线程执行结束,但是如果执行两次join则会造成程序终止,因此可以使用thread.joinable()来检查该线程是否可调用join()。

    thread.detach()的含义是将子线程从父线程中分离出去。当我们不使用任何thread时,main函数是在一个单进程中的单线程中,当我们创建一个线程时,main成为父线程,而新建的thread成为子线程。与join相同,detach也不能被调用两次,需要用joinable来进行检查。

    对于一个thread对象,必须调用join或者detach,否则,当该线程析构时,会终止当前的进程。即当析构时,该thread对象的状态为joinable的话,调用std::terminate;。c++标准explicit处理的原因是不利于debug,具体原因这里不进行展开。

    3 Mutex

    Mutex是Mutual Exclusion(互斥)的意思,std::mutex的作用是处理所谓的竞争问题(Race Condition),即两个线程同时对一个关键变量(Critical Section,即只能有一个线程或进程同时进行访问的一个或一组变量或状态)进行读写的问题。我们假设有一个变量int x = 0;,如果连个线程T1和T2同时对变量x进行++操作,则有可能导致两个

  • 相关阅读:
    淘宝/天猫获取淘宝直播分类id接口 API 返回值说明
    Java.lang.Class类 getInterfaces()方法有什么功能呢?
    使用 Databend 助力 MySQL 的数据分析
    Java集合List去重的几种方式
    基于springboot+mybatis+thymeleaf+redis+html实现的农村在线交易平台项目(含支付模块)
    为什么加载了两个OAuth2AuthorizationRequestRedirectFilter分析
    使用sngrep跟踪分析sip信令
    WinFrom、C# 学习记录四 WebView2使用记录
    【畅购商城】订单模块之收货人列表
    什么是“path”环境变量?path的作用是什么?
  • 原文地址:https://blog.csdn.net/m0_64407685/article/details/126843174