一 C++11多线程简介
C++11标准库会提供类thread
(std::thread
)。若要运行一个线程,可以创建一个类thread
的实体,其初始参数为一个函数对象,以及该函数对象所需要的参数。通过成员函数std::thread::join()
对线程会合的支持,一个线程可以暂停直到其它线程运行完毕。若有底层平台支持,成员函数std::thread::native_handle()
将可提供对原生线程对象运行平台特定的操作。对于线程间的同步,标准库将会提供适当的互斥锁(像是std::mutex
,std::recursive_mutex
等等)和条件参数(std::condition_variable
和std::condition_variable_any
)。前述同步机制将会以RAII锁(std::lock_guard
和std::unique_lock
)和锁相关算法的方式呈现,以方便程序员使用。
对于要求高性能,或是极底层的工作,有时或甚至是必须的,我们希望线程间的通信能避免互斥锁使用上的开销。以原子操作来访问内存可以达成此目的。针对不同情况,我们可以通过显性的内存屏障改变该访问内存动作的可见性。
对于线程间异步的传输,C++11标准库加入了以及std::packaged_task
用来包装一个会传回异步结果的函数调用。因为缺少结合数个future的功能,和无法判定一组promise集合中的某一个promise是否完成,futures此一提案因此而受到了批评。
更高级的线程支持,如线程池,已经决定留待在未来的TechnicalReport加入此类支持。更高级的线程支持不会是C++11的一部分,但设想是其最终实现将创建在目前已有的线程支持之上。
std::async
提供了一个简便方法以用来运行线程,并将线程绑定在std::future
。用户可以选择一个工作是要多个线程上异步的运行,或是在一个线程上运行并等待其所需要的数据。默认的情况,实现可以根据底层硬件选择前面两个选项的其中之一。另外在较简单的使用情形下,实现也可以利用线程池提供支持。
二 简单std::thread的使用
#include <iostream>
#include <thread>
using namespace std;
void myFirstThread()
{
cout << "Hello thread" << endl;
}
int main()
{
thread myThread(myFirstThread);
myThread.join();
return 0;
}
三 std::thread类构造函数函数简介
std::thread构造
1 默认构造,创建一个空的thread对象,以下为默认构造函数声明:
thread() noexcept;
2拷贝构造 copy-delete(thread对象不可拷贝构造):
thread (const thread&) = delete;
3初始化构造,创建thread对象,该对象可被joinable,线程会调用fn函数,参数由args给出,下边为初始化构造 函数声明:
template <class Fn, class... Args>
explicit thread (Fn&& fn,Args&&... args);
4移动构造 move,此构造函数调用成功之后,x不代表任何thread可执行对象。
thread (thread&& x) noexcept;
注意:可被joinable的thread对象必须在他们销毁之前被主线程join或者将之设置为detached。
std::thread各种构造函数示例如下:
#include <iostream> #include <thread> using namespace std; void myFirstThreadTask(int num) { for (int i = 0; i < 10; ++i) { cout << "myFirstThreadTask's num = " << num++ << endl; this_thread::sleep_for(chrono::milliseconds(10)); } } void mySecondThreadTask(int &num) { for (int i = 0; i < 10; ++i) { cout << "mySecondThreadTask's num = " << num++ << endl; this_thread::sleep_for(std::chrono::milliseconds(10)); } } int main(int argc, _TCHAR* argv[]) { int n = 5; thread myThread0;//myThread1为一个空线程,不代表任何可执行对象 //myThread1与myFirstThreadTask函数绑定,n为其按值传递参数 thread myThread1(myFirstThreadTask,n); //myThread2与mySecondThreadTask函数绑定,n为其引用传递参数 thread myThread2(mySecondThreadTask,std::ref(n)); //现在myThread2不代表任何可执行对象,myThread3与mySecondThreadTask函数绑定 thread myThread3(std::move(myThread2)); myThread1.join(); myThread3.join(); //myThread3.join(); return 0; }