《C++ Concurrencyin Action》读书笔记
1、使用g++编译多线程程序的时候需要加上-lpthread参数,如:
g++ -std=c++11–o run.out test.cpp –lpthread
2、多线程编程增加了头文件#include<thread>,标准c++库中对多线程支持的声明在新的头文件中,管理现成的函数和类在<thread>中声明,而保护共享数据的函数和类在其他头文件中声明。每个线程都必须具有一个初始函数,新线程的执行在这里开始,一般初始线程的main()函数,对于其他线程,可以在std::thread对象的构造函数中指定。
例子:
#include<iostream>
#include<thread>
using namespace std;
void thread_hello()
{
Cout <<“hello thread”<<endl;
}
Int main(void)
{
Threadt(thread_hello);
t.join();
//t.detach();
return 0;
}//end
Join:线程的加入,可以确保线程在函数完成前结束,能保证局部变量在县城完成后才被销毁;jion()只能对给定的对象调用一次,如果对给已加入的线程再次join()操作时,将会导致错误,可以调用joinable()进行判断是否已经加入。
Detach:线程的分离,主调函数不等待线程结束。使用detach()会让线程在后台运行,意味着主线程不能与之直接交互。通常分离线程为守护线程(没有任何用户接口,并在后台运行的线程)。
3、在把函数对象传入到线程构造函数中时,需要注意:如果传递了一个临时变量(非命名的变量),c++编译器会将其解析为函数生命,而不是类型对象的定义,例如:
Std::threadmy_thread(test_thread());
这里相当于声明了一个带有一个参数名为my_thread并但会一个std::thread对象的函数。解决这个问题的四种方式:
1) 在前面命名函数对象;
2) 使用多组括号,std::thread my_thread((test_thread()));
3) 使用c++11新的初始化语法:std::thread my_thread{test_thread()};//大括号括起来;
4) 使用lambda表达式(允许使用一个可以捕获局部变量的局部函数)。
4、为了防止主调函数执行完成后(使用了detach),新线程还在运行(可能会访问到已经销毁的变量),常规方法:使线程函数的功能齐全,将数据复制到县城中,而不是复制到共享数据中(引用和指针的不当使用)。
5、什么情况下使用分离线程:一个程序执行多个相同的线程人物,每个线程运行相同的代码,但是每个线程都是独立的,完成与否对其他线程都不会产生影响。
6、向线程函数传递参数,例:
Void func(int i , std::string const&s);
Std::thread t(func, 3, “hello”);//注意字面值常量(char const *)向std::string对象的转化
还可以传递一个成员函数指针作为线程函数,并提供一个合适的对象指针作为第一个参数。
7、不能通过赋一个新值给std::thread对象的方式来“丢弃”一个线程,std::thread支持移动,就意味着新线程的所有权可以在函数外进行转移。例:
Std::thread f()
{
Void some_func();
Return std::thread(some_func);
/*或者如下定义:
*std::thread t(some_func);
*return t;*/
}
8、当所有权可以在函数内部传递,就允许std::thread实例可作为参数进行传递。例:
Void f(std::threadt);
F(std::thread(some_function));
9、std::thread::hardware_concurrency(),该函数返回能同时并发在一个程序中的线程数量(多核系统中,返回值是cpu核心的数量)。
10、在确定了要使用的线程数量之后,通过创建一个std::vector<T>容器存放中间结果,并为线程创建一个std::vector<std::thread>容器,需要注意:启动线程的数量必须比num_threads小1,因为在启动之前已经有了一个主线程。
11、线程标识类型是std::thread::id,以两种方式可以获取:
1)通过调用std::thread对象的成员函数get_id()来直接过去,如果std::thread对象没有与任何执行线程相关联,get_id()将返回std::thread::type默认构造值,这个值表示没有线程
2)当前线程中调用std::this_thread::get_id()(该函数也定义在<thread>头文件中)。
Std::thread::id对象可以自由的拷贝和对比,因为标识符就可以复用。如果两个对象的std::thread::id相等,那它们就是同一个线程,或者都没有线程。如果不等,那么就代表了两个不同线程,或者一个有线程一个没有。