zoukankan      html  css  js  c++  java
  • C++11多线程编程--线程创建

    参考资料

    线程的创建

    线程的创建有多种方式

    std::thread t1(可调用对象);

    由于实现(内部的实现这里不在探讨),std::thread()创建一个新的线程可以接受任意的可调用对象类型(带参数或者不带参数),包括lambda表达式(带变量捕获或者不带),函数,函数对象,以及函数指针。

    下面简单的探讨一下。

    1.通过一个不带参数的函数创建线程。

    #include <iostream>
    #include <thread> // 多线程头文件
    
    void Hello() {
      std::cout << "Hello, World!" << std::endl;
    }
    
    int main() {
      // 创建一个线程对象,注意函数 Hello 将立即运行。
      std::thread t(&Hello);
    
      // 等待线程结束。
      // 否则线程还没执行(完),主程序就已经结束了。
      t.join();
    
      return 0;
    }
    

    cppreference 关于立即运行有提到

    在启动了一个线程(创建了一个thread对象)之后,当这个线程结束的时候(std::terminate()),我们如何去回收线程所使用的资源呢?
    thread库给我们两种选择:

    • 1.加入式(join())
    • 2.分离式(detach())

    值得一提的是,你必须在thread对象销毁之前做出选择 这是因为线程可能在你加入或分离线程之前,就已经结束了,之后如果再去分离它,线程可能会在thread对象销毁之后继续运行下去。

    2.通过一个带参数的函数创建线程。

    #include <iostream>
    #include <thread>
    
    void Hello(const char* what) {
      // 睡眠一秒以模拟数据处理。
      std::this_thread::sleep_for(std::chrono::seconds(1));
      std::cout << "Hello, " << what << "!" << std::endl;
    }
    
    int main() {
      std::thread t(&Hello, "World");
      
      // 等价于使用 bind:
      //   std::thread t(std::bind(&Hello, "World"));
    
      t.join();
    
      return 0;
    }
    

    3.通过一个函数对象——即仿函数(functor)——创建线程。

    class Hello {
    public:
      void operator()(const char* what) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        std::cout << "Hello, " << what << "!" << std::endl;
      }
    };
    
    int main() {
      Hello hello;
    
      // 方式一:拷贝函数对象。
      std::thread t1(hello, "World");
      t1.join();
    
      // 方式二:不拷贝函数对象,通过 boost::ref 传入引用。
      // 用户必须保证被线程引用的函数对象,拥有超出线程的生命期。
      // 比如这里通过 join 线程保证了这一点。 
      std::thread t2(std::ref(hello), "World");
      t2.
    
      return 0;
    }
    

    4.通过一个成员函数创建线程。

    // 通过成员函数来创建线程. 注意和普通函数的区别
    #include <thread>
    #include <iostream>
    
    class Hello {
    public:
        void ThreadFuntion() {
            std::this_thread::sleep_for(std::chrono::seconds(5));
            std::cout << "ThreadFuntion1 " << std::this_thread::get_id() << std::endl;
        }
    };
    
    
    int main() {
        Hello hello; // 需要一个对象
        std::thread t1(&Hello::ThreadFuntion, &hello);
        t1.join();
    
        return 0;
    }
    

    5.通过一个成员函数创建线程(在构造函数中操作)。

    与前例不同之处在于,需要以 bind 绑定 this 指针作为第一个参数。

    #include <iostream>
    #include <thread>
    
    class Hello {
    public:
      Hello() {
        std::thread t(std::bind(&Hello::Entry, this, "World"));
        t.join();
      }
    
    private:
      // 线程函数
      void Entry(const char* what) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        std::cout << "Hello, " << what << "!" << std::endl;
      }
    };
    
    int main() {
      Hello hello;
      return 0;
    }
    

    6.使用lambda

    #include <iostream>
    #include <thread>
    
    //
    int main() {
        auto threadFunction = []() {
            std::cout << "Lambda thread id " << std::this_thread::get_id() <<std::endl; // 打印线程id
            std::cout << "使用lambda表达式作为可调用对象" << std::endl;
        };
    
        std::cout <<  "Main thread id " << std::this_thread::get_id() <<std::endl;
        std::thread t1(threadFunction);
        t1.join();
        return 0;
    }
    
    

    join Vs detach

    join

    join()字面意思是连接一个线程,意味着主动地等待线程的终止。
    join()是这样工作的,在调用进程中join(),当新的线程终止时,join()会清理相关的资源(any storage associated with the thread),然后返回,调用线程再继续向下执行。 正是由于join()清理了线程的相关资源,因而我们之前的thread对象与已销毁的线程就没有关系了,这意味着一个线程的对象每次你只能使用一次join(),当你调用的join()之后joinable()就将返回false了。

    关于joinable()
    判断是否可以成功使用join() 或者detach(), 返回值为bool .

    #include <iostream>
    #include <thread>
    
    void foo()
    {
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
      
    int main()
    {
        std::thread t(foo);
        std::cout << "before joining,joinable=" << std::boolalpha << t.joinable() << std::endl;
        t.join();
        std::cout << "after joining, joinable=" << std::boolalpha << t.joinable() << '
    ';
    }
    
    // output 
    // [thread]main
    // before joining,joinable=true
    // after joining, joinable=false
    

    detach

    分离式,对应的函数是detach()。
    detach这个词的意思是分离的意思,对一个thread对象使用detach()意味着从调用线程分理出这个新的线程,我们称分离的线程叫做守护线程(daemon threads)。之后也就不能再与这个线程交互。
    分离的线程会在后台运行,其所有权(ownership)和控制权将会交给c++运行库。同时,C++运行库保证,当线程退出时,其相关资源的能够正确的回收。
    分离的线程,它运行结束后,不再需要通知调用它的线程

    线程的标识

    线程id。
    类 thread::id 是轻量的可频繁复制类,它作为 std::thread 对象的唯一标识符工作。

    • std::this_thread::get_id()这个函数获取线程的标识符 (在线程的函数中)
    • 线程对象也有一个function get_id() std::thread::id get_id() const noexcept;
    // source: cppreference
    #include <iostream>
    #include <thread>
    #include <chrono>
     
    void foo()
    {
        // 看这里
        std::cout << std::this_thread::get_id() <<std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
     
    int main()
    {
        // 看这里
        std::thread t1(foo);
        std::thread::id t1_id = t1.get_id();
     
        std::thread t2(foo);
        std::thread::id t2_id = t2.get_id();
     
        std::cout << "t1's id: " << t1_id << '
    ';
        std::cout << "t2's id: " << t2_id << '
    ';
     
        t1.join();
        t2.join();
    }
    
  • 相关阅读:
    poj 1088 滑雪
    位运算与bitset
    hdu 4607 Park Visit
    树的直径
    codeforces 495D Sonya and Matrix
    German Collegiate Programming Contest 2015(第三场)
    BAPC 2014 Preliminary(第一场)
    Benelux Algorithm Programming Contest 2014 Final(第二场)
    E. Reachability from the Capital(tarjan+dfs)
    poj2104 K-th Number(划分树)
  • 原文地址:https://www.cnblogs.com/__tudou__/p/11296463.html
Copyright © 2011-2022 走看看