首页 > C++多线程:thread类创建线程的多种方式

C++多线程:thread类创建线程的多种方式

文章目录

      • 描述
      • 函数成员简介
      • 总结

描述

  • 头文件

  • 声明方式:std::thread

  • 简介

    线程在构造关联的线程对象时立即开始执行,从提供给作为构造函数参数的顶层函数开始。如果顶层函数抛出异常,则调用 std::terminate。正如我们之前几篇说过的thread可以通过std::asyncstd::promise类对修改共享变量,并将返回值传递给调用方。如果共享变量在该过程中需要进行同步,则就需要我们说过的std::mutexstd::condition_variable

    std::thread不支持拷贝构造和赋值,如果需要将当前t1 对象赋值给t2对象,需要通过移动赋值std::move,即将t1的地址以及内容全部赋值给t2对象才行。

函数成员简介

  • 构造函数(创建线程的多种方式)

    a. 类对象的拷贝创建线程

    b. 类对象的引用创建线程

    c. 移动复制std::move对象创建线程

    d. 临时创建的对象创建线程

    e. 函数名创建线程

    f. lamda函数创建线程

    g. 类对象的拷贝的成员函数 创建线程

    h. 类对象的地址的成员函数 创建线程
    #include 
    #include 
    #include 
    #include void f1(int n)
    { for (int i = 0; i < 5; ++i) { std::cout << "Thread 1 executing
    ";++n;std::this_thread::sleep_for(std::chrono::milliseconds(10));}
    }void f2(int& n)
    { for (int i = 0; i < 5; ++i) { std::cout << "Thread 2 executing
    ";++n;std::this_thread::sleep_for(std::chrono::milliseconds(10));}
    }class foo
    { 
    public:void bar(){ for (int i = 0; i < 5; ++i) { std::cout << "Thread 3 executing
    ";++n;std::this_thread::sleep_for(std::chrono::milliseconds(10));}}int n = 0;
    };class baz
    { 
    public:void operator()(int n){ for (int i = 0; i < 5; ++i) { std::cout << "Thread 4 executing
    ";++n;std::this_thread::sleep_for(std::chrono::milliseconds(10));}}int n = 0;
    };int main()
    { int n = 0;foo f;baz b;std::thread t1; // t1 is not a threadstd::thread t2(f1, n + 1); // 普通函数名创建线程,传递函数参数为值std::thread t3(f2, std::ref(n)); // 普通函数名创建线程,传递函数参数为引用std::thread t4(std::move(t3)); // 类对象的移动赋值,使用std::movestd::thread t5(&foo::bar, &f); // 类对象的拷贝的地址的成员函数std::thread t6(b,6); // 类对象创建线程,默认执行operator ()函数std::thread t7([](int x){ return x*x;},6);//lamda函数创建子线程std::thread t8(std::ref(b),6);//类对象的引用创建std::thread t9(baz(),6);//临时对象创建t2.join();t4.join();t5.join();t6.join();t7.join();t8.join();t9.join();std::cout << "Final value of n is " << n << '
    ';std::cout << "Final value of foo::n is " << f.n << '
    ';
    }
    
    输出如下,由于输出为线程间交叉执行,输出会有点乱:
    Thread 2 executing
    Thread 4 executing
    Thread 1 executing
    Thread 3 executing
    Thread 4 executing
    Thread 4 executing
    Thread 2 executing
    Thread 1 executing
    Thread 3 executing
    Thread 4 executing
    Thread 4 executing
    Thread 4 executing
    Thread 2 executing
    Thread 1 executing
    Thread 4 executing
    Thread 3 executing
    Thread 4 executing
    Thread 4 executing
    Thread 2 executing
    Thread 4 executing
    Thread 4 executing
    Thread 1 executing
    Thread 3 executing
    Thread 4 executing
    Thread 2 executing
    Thread 4 executing
    Thread 4 executing
    Thread 3 executing
    Thread 4 executing
    Thread 1 executing
    Final value of n is 5
    Final value of foo::n is 5
    
  • std::thread::joinable检查 thread 对象是否标识活跃的执行线程,是返回true,否则返回false

    如下代码
    #include 
    #include 
    #include void foo()
    { std::this_thread::sleep_for(std::chrono::seconds(1));
    }int main()
    { //刚创建好的线程对象是不活跃的std::thread t;std::cout << "before starting, joinable: " << std::boolalpha << t.joinable()<< '
    ';//创建线程并执行代码,但未合并,则它是活跃的t = std::thread(foo);std::cout << "after starting, joinable: " << t.joinable() << '
    ';//线程合并之后变为不活跃的t.join();std::cout << "after joining, joinable: " << t.joinable() << '
    ';
    }
    
    输出如下:
    before starting, joinable: false
    after starting, joinable: true
    after joining, joinable: false
    
  • std::thread::join阻塞线程成员,直到线程函数代码执行完毕返回

    代码如下:
    #include 
    #include 
    #include void foo()
    { std::this_thread::sleep_for(std::chrono::seconds(1));
    }void bar()
    { std::this_thread::sleep_for(std::chrono::seconds(1));
    }int main()
    { std::cout << "starting first helper...
    ";std::thread helper1(foo);std::cout << "starting second helper...
    ";std::thread helper2(bar);std::cout << "waiting for helpers to finish..." << std::endl;helper1.join();helper2.join();std::cout << "done!
    ";
    }
    
    输出如下:
    starting first helper...
    starting second helper...
    waiting for helpers to finish...
    done!
    
  • std::thread::detach从 thread 对象分离执行的线程,允许执行独立地执行线程

    一旦线程退出,则释放所有分配的资源。

    如下代码:
    #include 
    #include 
    #include void independentThread() 
    { std::cout << "Starting concurrent thread.
    ";std::this_thread::sleep_for(std::chrono::seconds(2));std::cout << "Exiting concurrent thread.
    ";
    }void threadCaller() 
    { std::cout << "Starting thread caller.
    ";std::thread t(independentThread);//这里调用detach,则线程t将独立执行,所以当前线程的输出会早于t线程的输出t.detach();std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "Exiting thread caller.
    ";
    }int main() 
    { threadCaller();std::this_thread::sleep_for(std::chrono::seconds(5));
    }
    
    输出如下:
    Starting thread caller.
    Starting concurrent thread.
    Exiting thread caller.
    Exiting concurrent thread.
    
  • std::thread::swap交换两个线程的对象的文件句柄

    代码如下:
    #include 
    #include 
    #include void foo()
    { std::this_thread::sleep_for(std::chrono::seconds(1));
    }void bar()
    { std::this_thread::sleep_for(std::chrono::seconds(1));
    }int main()
    { std::thread t1(foo);std::thread t2(bar);std::cout << "thread 1 id: " << t1.get_id() << std::endl;std::cout << "thread 2 id: " << t2.get_id() << std::endl;使用boost的swap和thread类封装的swap函数效果类似,都会交换线程的文件句柄std::swap(t1, t2);std::cout << "after std::swap(t1, t2):" << std::endl;std::cout << "thread 1 id: " << t1.get_id() << std::endl;std::cout << "thread 2 id: " << t2.get_id() << std::endl;t1.swap(t2);std::cout << "after t1.swap(t2):" << std::endl;std::cout << "thread 1 id: " << t1.get_id() << std::endl;std::cout << "thread 2 id: " << t2.get_id() << std::endl;t1.join();t2.join();
    }
    
    输出如下:
    thread 1 id: 0x70000f1e9000
    thread 2 id: 0x70000f26c000
    after std::swap(t1, t2):
    thread 1 id: 0x70000f26c000
    thread 2 id: 0x70000f1e9000
    after t1.swap(t2):
    thread 1 id: 0x70000f1e9000
    thread 2 id: 0x70000f26c000
    

总结

本文介绍了C++的多线程类thread的基本使用,在前面几篇文章的描述之下对C++多线程编程有了基本的使用能力。面向对象的编程让线程类在并发编程中发挥出了精妙的高效便捷优势,今后需要多多实践与体会C++并发编程的妙处。

更多相关:

  • 经过长期探索,发现一个不需要手动设置线程休眠时间(e.g. std::this_thread::sleep_for(std::chrono::microseconds(1)))的代码: Github: https://github.com/log4cplus/ThreadPool #ifndef THREAD_POOL_H_7e...

  • nth_element(first,nth,last) first,last 第一个和最后一个迭代器,也可以直接用数组的位置。  nth,要定位的第nn 个元素,能对它进行随机访问. 将第n_thn_th 元素放到它该放的位置上,左边元素都小于它,右边元素都大于它. 测试代码: http://www.cplusplus.com...

  • c/c++老版本的rand()存在一定的问题,在转换rand随机数的范围,类型或者分布时,常常会引入非随机性。 定义在 中的随机数库通过一组协作类来解决这类问题:随机数引擎 和 随机数分布类 一个给定的随机数发生器一直会生成相同的随机数序列。一个函数如果定义了局部的随机数发生器,应该将(引擎和分布对象)定义为 st...

  • jsoncpp 是一个C++ 语言实现的json库,非常方便得支持C++得各种数据类型到json 以及 json到各种数据类型的转化。 一个json 类型的数据如下: {"code" : 10.01,"files" : "","msg" : "","uploadid" : "UP000000" } 这种数据类型方便我们人阅读以...

  • 问题如下: 已知一组数(其中有重复元素),求这组数可以组成的所有子集中,子 集中的各个元素和为整数target的子集,结果中无重复的子集。 例如: nums[] = [10, 1, 2, 7, 6, 1, 5], target = 8 结果为: [[1, 7], [1, 2, 5], [2, 6], [1, 1, 6]] 同样之前有...