• c++11: <thread>学习


    <thread>头文件中包含thread类与this_thread命名空间,下面逐一介绍。

    thread

    1. 构造函数

    (1)默认构造函数

    thread() noexcept;

    默认构造函数不执行任何线程,产生线程对象的线程ID为0。

    (2)初始化构造函数

    template <class Fn, class... Args>

    explicit thread (Fn&& fn, Args&&... args);

    产生一个thread对象,提供一个joinable的线程并开始执行。joinable的线程在它们被销毁前需要被joindetach(否则线程资源不会被完全释放)。

    参数介绍:

    fn: 指向函数的指针,指向成员函数的指针,或者任何有移动构造函数(?)的对象(例如重载了operator()的类对象,闭包和函数对象)。如果有返回值的话,返回值被丢弃。

    arg…: 传递给fn的参数。它们的类型必须是可移动构造的(?)。如果fn是成员函数指针的话,第一个参数必须是调用此方法的对象(或者引用/指针)。

    (3)拷贝构造函数

    thread (const thread&) = delete;

    删除拷贝构造函数(线程对象不能被拷贝)。

    (4)移动构造函数

    thread (thread&& x) noexcept;

    如果x是一个线程的话,生成一个新的线程对象。这个操作不影响原线程运行,只是将线程的拥有者从x变为新对象,此时x不再代表任何线程(移交了控制权)。

    参数介绍:

    x: 要移动给构造构造函数的另一线程对象。

    例子

    // constructing threads
    #include <iostream>       // std::cout
    #include <atomic>         // std::atomic
    #include <thread>         // std::thread
    #include <vector>         // std::vector
    
    std::atomic<int> global_counter (0);
    
    void increase_global (int n) { for (int i=0; i<n; ++i) ++global_counter; }
    
    void increase_reference (std::atomic<int>& variable, int n) { for (int i=0; i<n; ++i) ++variable; }
    
    struct C : std::atomic<int> {
      C() : std::atomic<int>(0) {}
      void increase_member (int n) { for (int i=0; i<n; ++i) fetch_add(1); }
    };
    
    int main ()
    {
      std::vector<std::thread> threads;
    
      std::cout << "increase global counter with 10 threads...
    ";
      for (int i=1; i<=10; ++i)
        threads.push_back(std::thread(increase_global,1000));
    
      std::cout << "increase counter (foo) with 10 threads using reference...
    ";
      std::atomic<int> foo(0);
      for (int i=1; i<=10; ++i)
        threads.push_back(std::thread(increase_reference,std::ref(foo),1000));
    
      std::cout << "increase counter (bar) with 10 threads using member...
    ";
      C bar;
      for (int i=1; i<=10; ++i)
        threads.push_back(std::thread(&C::increase_member,std::ref(bar),1000));
    
      std::cout << "synchronizing all threads...
    ";
      for (auto& th : threads) th.join();
    
      std::cout << "global_counter: " << global_counter << '
    ';
      std::cout << "foo: " << foo << '
    ';
      std::cout << "bar: " << bar << '
    ';
    
      return 0;
    }

    显示结果

    increase global counter using 10 threads...
    increase counter (foo) with 10 threads using reference...
    increase counter (bar) with 10 threads using member...
    synchronizing all threads...
    global_counter: 10000
    foo: 10000
    bar: 10000

    2. 析构函数

    ~thread();

    如果线程是joinable的,在销毁时会调用terminate();

    3. 成员函数

    (1)void detach();

    使该线程不再由调用线程的对象所管理(意味着调用线程不用再使用join方法),让该线程自己独立的运行。两个线程均不再阻塞,同步执行。当一个线程结束执行时,回释放它自己使用的资源。当调用了这个方法后,线程对象变成non-joinable状态,可以被安全删除。

    例子

    #include <iostream>       // std::cout
    #include <thread>         // std::thread, std::this_thread::sleep_for
    #include <chrono>         // std::chrono::seconds
     
    void pause_thread(int n) 
    {
      std::this_thread::sleep_for (std::chrono::seconds(n));
      std::cout << "pause of " << n << " seconds ended
    ";
    }
     
    int main() 
    {
      std::cout << "Spawning and detaching 3 threads...
    ";
      std::thread (pause_thread,1).detach();
      std::thread (pause_thread,2).detach();
      std::thread (pause_thread,3).detach();
      std::cout << "Done spawning threads.
    ";
    
      std::cout << "(the main thread will now pause for 5 seconds)
    ";
      // give the detached threads time to finish (but not guaranteed!):
      pause_thread(5);
      return 0;
    }

    结果

    Spawning and detaching 3 threads...
    Done spawning threads.
    (the main thread will now pause for 5 seconds)
    pause of 1 seconds ended
    pause of 2 seconds ended
    pause of 3 seconds ended
    pause of 5 seconds ended

    (2)id get_id() const noexcept;

    取得线程id

    如果线程对象是joinable的,这个方法返回一个唯一的线程id。

    如果线程对象不是joinable的,这个方法返回默认构造对象的id(为0)。

    (3)void join();

    调用这个函数的主线程会被阻塞直到子线程结束,子线程结束后有一些资源通过主线程回收。当调用这个函数之后,子线程对象变成non-joinable状态,可以安全销毁。该函数目的是防止主线程在子线程结束前销毁,导致资源未成功回收。

    例子

    // example for thread::join
    #include <iostream>       // std::cout
    #include <thread>         // std::thread, std::this_thread::sleep_for
    #include <chrono>         // std::chrono::seconds
     
    void pause_thread(int n) 
    {
      std::this_thread::sleep_for (std::chrono::seconds(n));
      std::cout << "pause of " << n << " seconds ended
    ";
    }
     
    int main() 
    {
      std::cout << "Spawning 3 threads...
    ";
      std::thread t1 (pause_thread,1);
      std::thread t2 (pause_thread,2);
      std::thread t3 (pause_thread,3);
      std::cout << "Done spawning threads. Now waiting for them to join:
    ";
      t1.join();
      t2.join();
      t3.join();
      std::cout << "All threads joined!
    ";
    
      return 0;
    }

    结果

    Spawning 3 threads...
    Done spawning threads. Now waiting for them to join:
    pause of 1 seconds ended
    pause of 2 seconds ended
    pause of 3 seconds ended
    All threads joined!

    (4)bool joinable() const noexcept;

    返回线程的joinable状态。

    如果一个线程对象是作为一个线程执行的它就是joinable的。

    当线程是如下情况的时候就不是joinable的

    a. 如果是用默认构造函数产生的(未执行)。

    b. 如果它曾被作为移动构造函数的参数(x)。

    c. 如果它曾被join或者detach过。

    (5)native_handle_type native_handle();

    返回A value of member type thread::native_handle_type.

    待续…

  • 相关阅读:
    创建进程
    进程
    操作系统历史
    socket
    网络基础
    常用模块二:hashlib、configparser、logging
    常见正则匹配
    类中的内置方法(魔法方法、双下方法)
    反射、isinstance和issubclass
    封装、继承、多态
  • 原文地址:https://www.cnblogs.com/shibo/p/4412189.html
Copyright © 2020-2023  润新知