c++11 多线程(1) thread 总结


本文主要是针对C++中多线程并发操作参见(cplusplus)进行解释,文章从下面几个方面进行学习,分别介绍多线程中会使用到的几个文件学习。 文中代码 可编译运行版本已上传在本人github(地址)

多线程

C++ 中关于并发多线程的部分,主要包含 <thread>、<mutex>、<atomic>、<condition_varible>、<future>五个部分。

  • <atomic>:该头文主要声明了两个类, std::atomic 和 std::atomic_flag,另外还声明了一套 C 风格的原子类型和与 C 兼容的原子操作的函数。
  • <thread>:该头文件主要声明了 std::thread 类,另外 std::this_thread 命名空间也在该头文件中。
  • <mutex>:该头文件主要声明了与互斥量(mutex)相关的类,包括 std::mutex 系列类,std::lock_guard, std::unique_lock, 以及其他的类型和函数。
  • <condition_variable>:该头文件主要声明了与条件变量相关的类,包括 std::condition_variable 和 std::condition_variable_any。
  • <future>:该头文件主要声明了 std::promise, std::package_task 两个 Provider 类,以及 std::future 和 std::shared_future 两个 Future 类,另外还有一些与之相关的类型和函数,std::async() 函数就声明在此头文件中。

1、 thread

本节讲thread头文件中的内容,练习代码地址;
<thread> 头文件中声明:thread线程和命名空间this_thread; thread包含如下:

(一)、Member types
id Thread id (public member type )
native_handle_type Native handle type (public member type )

std::thread::id是线程调用get_id和this_thread::get_id的返回值;thread::id默认构造函数的结果是一个non-joinable的值;通常用来和其他线程 thread::get_id的结果做比较。
std::thread::native_handle_type本地句柄类型,如果库实现支持它,这个成员类型只存在于类线程中。是thread类成员函数thread::native_handle的返回值。
定义: typedef /* implementation-defined */ native_handle_type;

(二)、Member functions
(constructor) Construct thread (public member function )
(destructor) Thread destructor (public member function )
operator= Move-assign thread (public member function )
get_id Get thread id (public member function )
joinable Check if joinable (public member function )
join Join thread (public member function )
detach Detach thread (public member function )
swap Swap threads (public member function )
native_handle Get native handle (public member function )
hardware_concurrency [static] Detect hardware concurrency (public static member function )

示例 1:

// thread example
#include  <iostream>        // std::cout
#include  <thread>        // std::thread
void foo()  { 
    std::cout << "foo is called" << std::endl;
}
void bar(int x) {
     std::cout << "bar is called" << std::endl;
}

int main()
{
     std::thread first (foo);    // spawn new thread that calls foo()
     std::thread second (bar,0);  // spawn new thread that calls bar(0)                                                 
     std::cout << "main, foo and bar now execute concurrently...\n";
     // synchronize threads:
     first.join();                // pauses until first finishes
     second.join();              // pauses until second finishes
     std::cout << "foo and bar completed.\n";
     return 0;
}
default (1)              thread() noexcept;   
initialization (2)       template <class Fn, class... Args>  
                           explicit thread (Fn&& fn, Args&&... args);
copy [deleted] (3)     thread (const thread&) = delete;
move (4)                 thread (thread&& x) noexcept;

(1)默认构造函数
构造一个不表示任何执行线程的线程对象。
(2)初始化的构造函数 模版函数
构建一个线程对象,该对象表示一个新的可接合线程。新的执行线程调用fn传递args作为参数(使用其lvalue或rvalue引用的衰变副本)。此构建的完成开始同步调用fn副本的。
(3) 拷贝构造 不允许拷贝构造
(4) 移动构造 构造线程获取x线程,这个操作不会影响移动线程的执行,它只会传输它的处理程序。完成x将不再表示一个线程。
示例2

  // 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...\n";
    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...\n";
    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...\n";
    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...\n";
    for (auto& th : threads) th.join();

    std::cout << "global_counter: " << global_counter << '\n';
    std::cout << "foo: " << foo << '\n';
    std::cout << "bar: " << bar << '\n';

    return 0;
  }
  • 析构函数(destructor)
    std::thread::~thread破坏了线程对象。如果在销毁时线程是可接合的,则调用终止()。
  • std::thread::operator=:
    move (1) thread& operator= (thread&& rhs) noexcept;
    copy [deleted] (2) thread& operator= (const thread&) = delete;
    thread不允许拷贝;如果对象当前不是joinable的,它将获得由rhs(如果有的话)表示的执行线程。如果是joinable,则调用终止()。赋值“=”运算符通过右值表达式,复制后的thread对象不再是一个线程。
    示例3
  // example for thread::operator=
  #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\n";
  }

  int main() 
  {
    std::thread threads[5];                         // default-constructed threads

    std::cout << "Spawning 5 threads...\n";
    for (int i=0; i<5; ++i)
      threads[i] = std::thread(pause_thread,i+1);   // move-assign threads

    std::cout << "Done spawning threads. Now waiting for them to join:\n";
    for (int i=0; i<5; ++i)
      threads[i].join();

    std::cout << "All threads joined!\n";

    return 0;
  }
  • std::thread::get_id
    如果线程对象是joinable,函数将返回唯一标识线程的值。
    如果线程对象不可joinable,函数将返回成员类型线程的默认构造对象:id。
    示例4
  // thread::get_id / this_thread::get_id
  #include <iostream>       // std::cout
  #include <thread>         // std::thread, std::thread::id,   std::this_thread::get_id
  #include <chrono>         // std::chrono::seconds
 
  std::thread::id main_thread_id = std::this_thread::get_id();

  void is_main_thread() {
    if ( main_thread_id == std::this_thread::get_id() )
      std::cout << "This is the main thread.\n";
    else
      std::cout << "This is not the main thread.\n";
  }

  int main() 
  {
    is_main_thread();
    std::thread th (is_main_thread);
    th.join();
  }
  • std::thread::joinable
    返回线程对象是否可joinable。
    如果线程对象表示执行的线程,则是可joinable。
    在这些情况下,一个线程对象是不可连接的:

    • 如果是默认构造。
    • 如果它已经被移动(或者构造另一个线程对象,或者分配给它)。
    • 如果它的成员加入或分离被调用。

    示例5

  // example for thread::joinable
  #include <iostream>       // std::cout
  #include <thread>         // std::thread
 
  void mythread() 
  {
    // do stuff...
  }
 
  int main() 
  {
    std::thread foo;
    std::thread bar(mythread);

    std::cout << "Joinable after construction:\n" << std::boolalpha;
    std::cout << "foo: " << foo.joinable() << '\n';
    std::cout << "bar: " << bar.joinable() << '\n';

    if (foo.joinable()) foo.join();
    if (bar.joinable()) bar.join();

    std::cout << "Joinable after joining:\n" << std::boolalpha;
    std::cout << "foo: " << foo.joinable() << '\n';
    std::cout << "bar: " << bar.joinable() << '\n';

    return 0;
  }
  • std::thread::join
    join 函数在线程执行完成的时候返回;此函数在函数返回时与线程中所有操作的完成是同步的;调用join直到join被构造函数调用返回间,阻塞调用的线程;在调用此函数之后,线程对象变得不可连接,可以安全地销毁。
    示例6
  // 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\n";
  }
 
  int main() 
  {
    std::cout << "Spawning 3 threads...\n";
    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:\n";
    t1.join();
    t2.join();
    t3.join();
    std::cout << "All threads joined!\n";

    return 0;
  }
  • std::thread::detach
    detach分离出调用线程对象所代表的线程,允许它们彼此独立地执行;这两个线程在任何方式上都不阻塞或同步;注意,当一个结束执行时,它的资源被释放。在调用此函数之后,线程对象变得不可连接,可以安全地销毁。
    示例7
  #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\n";
  }
   
  int main() 
  {
    std::cout << "Spawning and detaching 3 threads...\n";
    std::thread (pause_thread,1).detach();
    std::thread (pause_thread,2).detach();
    std::thread (pause_thread,3).detach();
    std::cout << "Done spawning threads.\n";

    std::cout << "(the main thread will now pause for 5 seconds)\n";
    // give the detached threads time to finish (but not guaranteed!):
    pause_thread(5);
    return 0;
  }
  • std::thread::swap
    void swap (thread& x) noexcept; // 与X交换对象状态。

  • std::thread::native_handle
    获取本地处理函数;如果库实现支持,这个成员函数只存在于类线程中;如果存在,它将返回用于访问与线程关联的特定于实现的信息的值。

  • std::thread::hardware_concurrency
    static unsigned hardware_concurrency() noexcept; //函数定义
    检测硬件并发,返回硬件线程上下文的数量。对这个值的解释是看具体的系统和实现,可能不是精确的,只是一个近似值。请注意,这并不需要匹配系统中可用的处理器或内核的实际数目:一个系统可以支持每个处理单元的多个线程,或者限制对程序的资源的访问。如果此值没有计算或被定义好,则函数返回0。

  • std::swap (thread)
    std::swap 跟前面提到的成员函数有所不同,他不是成员函数。函数定义:
    void swap (thread& x, thread& y) noexcept;
    交换线程对象x和y的状态;就像x.swap(y)被调用。

本文主要讲thread,下篇c++11 多线程(2)mutex总结

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容