C++11中线程、锁和条件变量的介绍

这篇文章主要介绍“C++11中线程、锁和条件变量的介绍”,在日常操作中,相信很多人在C++11中线程、锁和条件变量的介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++11中线程、锁和条件变量的介绍”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

std::thread类代表了一个可执行的线程,它来自头文件<thread>。与其它创建线程的API(比如 Windows API中的CreateThread)不同的是, 它可以使用普通函数、lambda函数以及仿函数(实现了operator()函数的类)。另外,它还允许向线程函数传递任意数量的参数。

#include <thread> void func()  { // do some work } int main()  {     std::thread t(func);     t.join(); return 0;  }

在上面的例子中,t是一个线程对象,函数func()运行于该线程之中。调用join函数后,该调用线程(本例中指的就是主线程)就会在join进来进行执行的线程t结束执行之前,一直处于阻塞状态。如果该线程函数执行结束后返回了一个值,该值也将被忽略。不过,该函数可以接受任意数量的参数。

void func(int i, double d, const std::string& s)  {      std::cout << i << ", " << d << ", " << s << std::endl;  } int main()  {     std::thread t(func, 1, 12.50, "sample");     t.join(); return 0;  }

尽管我们可以向线程函数传递任意数量的参数,但是,所有的参数都是按值传递的。如果需要将参数按引用进行传递,那么就一定要象下例所示一样,把该参数封装到 std::ref或者std::cref之中。

void func(int& a)  {     a++;  } int main()  { int a = 42;     std::thread t(func, std::ref(a));     t.join();        std::cout << a << std::endl; return 0;  }

上面程序打印结果为43,但要不是将a封装到std::ref之中的话,输出的将是42。

除join方法之外,这个线程类还提供了另外几个方法:

swap: 将两个线程对象的底层句柄进行交换

detatch: 允许执行该方法的线程独立于本线程对象的执行而继续执行。脱离后的线程就再也不能执行join了(你不能等待到它执行结束了)

<span style="font-family:'Courier New', Arial;font-size:9pt;line-height:1.5;">int</span><span style="font-family:'Courier New', Arial;font-size:9pt;line-height:1.5;"> main()</span> {      std::thread t(funct);      t.detach(); return 0;  }

有一点非常重要,值得注意:线程函数中要是抛出了异常的话,使用通常的try-catch方式是捕获不到该异常的。换句话说,下面这种做法行不通:

try {      std::thread t1(func);      std::thread t2(func);         t1.join();      t2.join();  } catch(const std::exception& ex)  {      std::cout << ex.what() << std::endl;  }

要在线程间传递异常,你可以先在线程函数中捕获它们,然后再将它们保存到一个合适的地方,随后再让另外一个线程从这个地方取得这些异常。

std::vector<std::exception_ptr>  g_exceptions; void throw_function()  { throw std::exception("something wrong happened");  } void func()  { try {        throw_function();     } catch(...)     {        std::lock_guard<std::mutex> lock(g_mutex);        g_exceptions.push_back(std::current_exception());     }  } int main()  {     g_exceptions.clear();      std::thread t(func);     t.join(); for(auto& e : g_exceptions)     { try { if(e != nullptr)           {              std::rethrow_exception(e);           }        } catch(const std::exception& e)        {           std::cout << e.what() << std::endl;        }     } return 0;  }

要获得更多关于捕获并传递异常的知识,你可以阅读在主线程中处理工作线程抛出的C++异常以及怎样才能在线程间传递异常?。

在深入讨论之前还有一点值得注意,头文件<thread>里还在命名空间std::this_thread中提供了一些辅助函数:

get_id: 返回胆怯线程的id

yield: 让调度器先运行其它的线程,这在忙于等待状态时很有用

sleep_for: 将当前线程置于阻塞状态,时间不少于参数所指定的时间段

sleep_util: 在指定的时刻来临前,一直将当前的线程置于阻塞状态

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。