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();
    }
    
  • 相关阅读:
    Android 使用Fragment,ViewPagerIndicator 制作csdn app主要框架
    关于activity_main.xml与fragment_main.xml
    在MAC OS 下配置python + Flask ,并支持pyCharm编辑器
    openshift云计算平台diy模式安装Python2.7+Flask
    flask程序部署在openshift上的一些注意事项
    windows下python+flask环境配置详细图文教程
    SegmentFault 2014黑客马拉松 北京 作品demo
    Flask —— 使用Python和OpenShift进行即时Web开发
    支付宝的简单使用
    iOS- 详解文本属性Attributes
  • 原文地址:https://www.cnblogs.com/__tudou__/p/11296463.html
Copyright © 2011-2022 走看看