C++ 11中的多线程技术
C++11 新标准中引入了四个头文件来支持多线程编程,他们分别是 <atomic>
,<thread>
,<mutex>
,<condition_variable>
和<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() 函数就声明在此头文件中。
简单示例:
#include <iostream> #include <thread> using namespace std; void thread_1() { cout << "hello from thread_1" << endl; } int main(int argc, char **argv) { thread t1(thread_1); /** join()相当于调用了两个函数:WaitForSingleObject、CloseHandle,事实上,在vc12中也是这么实现的 */ t1.join(); return 0; }
注意事项
-
若线程调用到的函数在一个类中,则必须将该函数声明为静态函数函数
因为静态成员函数属于静态全局区,线程可以共享这个区域,故可以各自调用
#include <iostream> #include <pthread.h> using namespace std; #define NUM_THREADS 5 class Hello { public: //多线程调用,声明为static static void* say_hello( void* args ) { cout << "hello..." << endl; } }; int main() { pthread_t tids[NUM_THREADS]; for( int i = 0; i < NUM_THREADS; ++i ) { int ret = pthread_create( &tids[i], NULL, Hello::say_hello, NULL ); if( ret != 0 ) { cout << "pthread_create error:error_code" << ret << endl; } } pthread_exit( NULL ); }
测试结果:
hello...
hello...
hello...
hello...
hello...
-
代码中如果没有
pthread_join
主线程会很快结束从而使整个进程结束,从而使创建的线程没有机会开始执行就结束了。加入pthread_join
后,主线程会一直等待直到等待的线程结束自己才结束,使创建的线程有机会执行。 -
线程创建时属性参数的设置pthread_attr_t及join功能的使用
线程的属性由结构体pthread_attr_t进行管理。
typedef struct { int detachstate; //线程的分离状态 int schedpolicy; //线程调度策略 struct sched_param schedparam; //线程的调度参数 int inheritsched; //线程的继承性 int scope; //线程的作用域 size_t guardsize; //线程栈末尾的警戒缓冲区大小 int stackaddr_set; void * stackaddr; //线程栈的位置 size_t stacksize; // 线程栈的大小 }pthread_attr_t;
示例:
#include <iostream> #include <pthread.h> using namespace std; #define NUM_THREADS 5 void* say_hello( void* args ) { cout << "hello in thread " << *(( int * )args) << endl; int status = 10 + *(( int * )args); //线程退出时添加退出的信息,status供主程序提取该线程的结束信息 pthread_exit( ( void* )status ); } int main() { pthread_t tids[NUM_THREADS]; int indexes[NUM_THREADS]; pthread_attr_t attr; //线程属性结构体,创建线程时加入的参数 pthread_attr_init( &attr ); //初始化 pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); //是设置你想要指定线程属性参数,这个参数表明这个线程是可以join连接的,join功能表示主程序可以等线程结束后再去做某事,实现了主程序和线程同步功能 for( int i = 0; i < NUM_THREADS; ++i ) { indexes[i] = i; int ret = pthread_create( &tids[i], &attr, say_hello, ( void* )&( indexes[i] ) ); if( ret != 0 ) { cout << "pthread_create error:error_code=" << ret << endl; } } pthread_attr_destroy( &attr ); //释放内存 void *status; for( int i = 0; i < NUM_THREADS; ++i ) { int ret = pthread_join( tids[i], &status ); //主程序join每个线程后取得每个线程的退出信息status if( ret != 0 ) { cout << "pthread_join error:error_code=" << ret << endl; } else { cout << "pthread_join get status:" << (long)status << endl; } } }
测试结果:
hello in thread hello in thread 1hello in thread 3 hello in thread 4 0 hello in thread 2 pthread_join get status:10 pthread_join get status:11 pthread_join get status:12 pthread_join get status:13 pthread_join get status:14