编译环境
编译器: g++ 4.5
编译选项: -std=c++0x
链接选项: –pthread
完整编译链接命令: g++ –O2 –o example example.cc -std=c++0x -pthread
头文件:
条目 | 头文件 |
thread | <thread> |
Mutual exclusion | <mutex> |
Condition variables | <condition_variable> |
Futures | <future> |
a 线程创建
I 从函数中创建
如果想在一个线程中执行一个函数 f ,那么这个线程可以这样创建:
std::thread t( f );
如果函数有参数,那么直接把参数列在后边即可:
void hello_from( const char* str const ) { std::cout << "hello from " << str << "\n"; } std::thread t( hello_from, "thread t" );
多个参数的函数也是如此:
void max( const long m, const long n ) { std::cout << "max(" << m << ", " << n << ")=" << (m>n?m:n) << "\n"; } std::thread t( max, 13, 31 );
可以依此类推到3个、4个……参数的函数情形。
只要不把 main 函数也弄进去,编译器统统接受:
void try_start_program_here() { std::thread t( main ); //error }
II 从对象/仿函数中创建
把仿函数依样搬进去:
struct say_hello { void operator()()const { std::cout << "Hello.\n"; } };
std::thread t( say_hello() );
把上边代码敲进去编译一下后,没有发现问题,链接后执行一下,没有看到 Hello. 打印出来, 这是因为编译器把这一行
std::thread t( say_hello() );
当成一个函数声明了(这个函数返回一个 std::thread 类型对象, 接受一个缺省的函数指针,这个函数指针返回一个 say_hello 类型对象,并且无参数)。
这是一个老问题了,从标准输入读取字符填充到一个 vector 的时候也曾有过这样的不便:
std::vector<std::string> vs( (std::istream_iterator<std::string>(cin)), std::istream_iterator<std::string>() );//parsed as an object std::vector<std::string> vs( std::istream_iterator<std::string>(cin), std::istream_iterator<std::string>() ); //parsed as a function
依样画葫芦,再套上一层括号搞定:
struct say_hello { void operator()()const { std::cout << "Hello.\n"; } };
std::thread t( (say_hello()) );
或者用时髦一点的 c++0x 引入的初始化语法:
struct say_hello { void operator()()const { std::cout << "Hello.\n"; } }; std::thread t{ say_hello() };
直接复制一个对象也成:
struct say_hello { void operator()()const { std::cout << "Hello.\n"; } }; say_hello sh; std::thread t( sh );
如果想消去对象复制的成本,那就传 reference :
struct say_hello { void operator()()const { std::cout << "Hello.\n"; } }; say_hello sh; std::thread t( std::ref(sh) );
这个 std::ref 也是 c++0x 引入的,需要多包含一个头文件:
#include <functional>
照着函数的处理方法,带参数的仿函数也这么干:
struct hello_from { void operator()()const { std::cout << "hello from default\n"; } void operator()( const char* const name ) { std::cout << "hello from " << name << "\n"; } }; std::thread t1{ hello_from() }; std::thread t2{ hello_from(), "http://www.cnblogs.com/feng_wang/" };
多个参数的仿函数情形依此类推。
需要参数进行初始化的对象也是如此:
struct say_something { private: std::string name_; public: say_something( const std::string& name ) : name(name_) {} void operator()(const std::string& what) const { std::cout << name << " said \"" << what << "\"\n"; } }; std::thread t( say_something( "feng" ), "welcome." );
调用对象中的方法的时候则需要提供对象本身:
struct say_hello { void say( const std::string& what ) const { std::cout << what << "\n"; } }; say_hello s; std::thread t( &say_hello::say, &s, "hello" );
提供一个指针也可以:
struct say_hello { void say( const std::string& what ) const { std::cout << what << "\n"; } }; say_hello* s = new say_hello; std::thread t( &say_hello::say, s, "hello" );
不过为了防止这个线程执行过程中所传入的指针被另外一个线程意外释放,最好用智能指针 shared_ptr
struct say_hello { void say( const std::string& what ) const { std::cout << what << "\n"; } }; std::shared_ptr<say_hello> s ( new say_hello ); std::thread t( &say_hello::say, s, "hello" );
shared_ptr 也是 c++0x 提供的,为了使用它,需要
#include <memory>
当然,如果线程调用对象中的一个 static 方法就不需要提供对象本身了(注意 static 的方法不能有 c-v 限定):
struct say_hello { static void say( const std::string& what ) { std::cout << what << "\n"; } }; std::thread t( &say_hello::say, "hello" );
b 等待线程完结或者取消等待
这个很简单,单线程的时候只有 main 这一个线程,现在有了多线程之后,可以在创建新线程的线程中选择是否等待本线程创建的线程执行结束,还是直接返回:
等待完成:
//thread A void f(); std::thread t( f ); t.join();
直接结束:
void f(); std::thread t( f ); t.detach();
上边说了这么多,给出一个完整的例子结束本篇:
#include <iostream> #include <thread> void thanks() { std::cout << "Thank you for your reading.\n"; }; int main() { std::thread t( thanks ); t.join(); return 0; }