【C++】多线程【一】ios
part 0:多线程简介
Thread是一个指令序列,它能够在多线程环境中与其余这样的序列同时执行,同时共享同一个地址空间。算法
Thread is a sequence of instructions that can be executed concurrently with other such sequences in multithreading environments, while sharing a same address spac.多线程
Member types | Description | 成员类型 | |
---|---|---|---|
id | It is a values of this type are returned by thread::get_id and this_thread::get_id to identify threads. | It is a thread id.表示线程的id | 1 |
native_handle_type | It is a member type and it presents in class thread if the library implementation supports it. | 实现定义It is a native handle type. | 2 |
Member functions | 成员函数 | ||
constructor | It is used to construct thread. | 构造新的 thread 对象 | 3 |
destructor | It is used to destructor thread. | 析构 thread 对象,必须合并或分离底层线程 | 4 |
operator= | It is a move-assign thread. | 移动 thread 对象 | 5 |
get_id | It is used to get thread id. | 返回线程的 *id | 6 |
joinable | It is used to check if joinable. | 检查线程是否可合并,即潜在地运行于平行环境中 | 7 |
join | It is used to join thread. | 等待线程完成其执行 | 8 |
detach | It is used to detach thread. | 允许线程从线程句柄独立开来执行 | 9 |
swap | It is used to swap threads. | 交换二个 thread 对象 |
10 |
native_handle | It is used to get native handle. | 返回底层实现定义的线程句柄 | 11 |
hardware_concurrency | It is used to detect hardware concurrency. | 返回实现支持的并发线程数 | 12 |
Non-member overload & description | 非成员函数 | ||
swap | It is used to swap threads. | 特化 std::swap 算法 | 13 |
part 1:多线程构造
它用于构造线程对象。
It is used to constructs a thread object.并发
如下是std :: thread :: thread函数的声明。ide
thread() noexcept; template <class Fn, class... Args> explicit thread (Fn&& fn, Args&&... args); thread (const thread&) = delete; thread (thread&& x) noexcept;
参量
- **fn-**它是函数的指针,成员的指针或任何可移动构造的函数对象。
- **args …-**传递给fn调用的参数。
- **x-**这是一个线程对象。
#include <thread> //头文件 #include <iostream> using namespace std; void fn1(void) { cout << "fn1" << endl; } void fn2(int a) { cout << "fn2 " << a << endl; } void fn3(int& a) { cout << "fn3 " << a << endl; } class cls { public: void fn1(int a) { cout << "cls::fn1" << endl; } }; void test01() { std::thread t1(&fn1); //线程对象构造后,即开始执行 //可被 joinable 的 thread 对象必须在他们销毁以前被主线程 join 或者将其设置为 detached t1.join(); //必须执行join,否则运行期错误 std::thread t2(&fn2, 2); //传入函数参数 t2.join(); int n = 2; std::thread t3(&fn3, std::ref(n)); //传入引用参数 t3.join(); cls c; //线程入口为类成员函数 std::thread t4(&cls::fn1, &c, 2); t4.join(); } int main() { test01(); getchar(); return 0; }
cpp多线程并发 头文件的使用,正则化实现函数
#include <iostream> #include <thread> int main(void) { std::thread x([]()->void { int i = 4; while (i--) { std::this_thread::sleep_for(std::chrono::seconds(2)); std::cout << "*" << std::endl; } return; }); std::thread y([]()->void { int i = 4; while (i--) { std::this_thread::sleep_for(std::chrono::seconds(5)); std::cout << "-" << std::endl; } return; }); std::cout << std::thread::hardware_concurrency() << std::endl; //检测计算机并发数 std::cout << "x.hand " << x.native_handle() << std::endl; std::cout << "y.hand " << y.native_handle() << std::endl; //脱离主线程后不能直接获取句柄,因此放输出语句后面后面 x.detach(); y.detach(); std::this_thread::sleep_for(std::chrono::seconds(30));//等待程序执行完成 return 0; }
part 2:多线程析构
它破坏线程对象。
It destroys the thread object. Following is the declaration for std::thread::~thread function.this
~thread();
part 3:多线程operator=
如下是std :: thread :: operator =函数的声明。url
It is used to move-assign thread. Following is the declaration for std::thread::operator= function.spa
thread& operator= (thread&& rhs) noexcept; thread& operator= (const thread&) = delete;
参量 Parameters
rhs − It is a othread object..net
RHS -这是一个othread对象。
返回值
它返回* this
Data races
rhs和对象均被修改。
Both rhs and the object are modified.
part 4:joinable 它返回线程ive对象是否可链接,则返回true,不然返回false。 表示的是否可链接状态.
It returns whether the thread object is joinable.
It returns true if the thread is joinable or else false.
#include <iostream> #include <thread> void foo02() { std::this_thread::sleep_for(std::chrono::seconds(2)); } void test02() {//joinable std::thread t2;//建立了线程对象 std::cout << "before joneable: " << t2.joinable() << std::endl; t2 = std::thread(foo02);//joinable //实例化std::thread对象时传递了“函数名/可调用对象” std::cout << "after joneable: " << t2.joinable() << std::endl; t2.join();//等待 std::cout << "after joining,joinable: " << t2.joinable()<<std::endl; } int main() { test02(); getchar(); return 0; }
part 5:多线程std :: thread :: get_id
Declaration
下面是std::thread::get_id函数的声明。 Following is the declaration for std::thread::get_id function.
id get_id() const noexcept;
C++11
id get_id() const noexcept;
Return Value:It returns the thread id.
Exceptions:No-throw guarantee − never throws exceptions.
Data races:he object is accessed.
#include <iostream> #include <thread> #include <chrono> void foo() { std::this_thread::sleep_for(std::chrono::seconds(1)); } int main() { std::thread sample(foo); std::thread::id sample_id = sample.get_id(); std::thread sample2(foo); std::thread::id sample2_id = sample2.get_id(); std::cout << "sample's id: " << sample_id << '\n'; std::cout << "sample2's id: " << sample2_id << '\n'; sample.join(); sample2.join(); }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RgA6jWST-1609517496473)(C:\Users\guoqi\AppData\Roaming\Typora\typora-user-images\1609344040208.png)]
part 6:native_handle 返回底层实现定义的线程句柄
Declaration:Following is the declaration for std::thread::native_handle function.
native_handle_type native_handle();
Return Value:It returns a value of member type thread::native_handle_type.
part 7:hardware_concurrency 返回实现支持的并发线程数
Description
It returns the number of hardware thread contexts.
static unsigned hardware_concurrency() noexcept;
Return Value
It returns the number of hardware thread contexts.
part 8:join 线程执行完成后返回
It returns when the thread execution has completed.
void foo03() { std::this_thread::sleep_for(std::chrono::seconds(2)); } void bar03() { std::this_thread::sleep_for(std::chrono::seconds(2)); } void test03() {//join 线程执行完成后返回 //It returns when the thread execution has completed. std::cout << " starting helping ...." << std::endl; std::thread helper3(foo02); std::cout << " starting another helping ...." << std::endl; std::thread helper3_2(bar03); std::cout << " waiting for helpers finish...." << std::endl; helper3.join();//线程执行完成后返回 helper3_2.join(); std::cout << " done!" << std::endl; } int main() { test03(); getchar(); return 0; }
part 9:detach 允许线程从线程句柄独立开来执行
Description
It returns when the thread execution has completed.
#include <iostream> #include <chrono> #include <thread> void independentThread() { std::cout << "Starting thread.\n"; std::this_thread::sleep_for(std::chrono::seconds(2)); std::cout << "Exiting previous thread.\n"; } void threadCaller() { std::cout << "Starting thread caller.\n"; std::thread t(independentThread); t.detach(); std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout << "Exiting thread caller.\n"; } int main() { threadCaller(); std::this_thread::sleep_for(std::chrono::seconds(5)); }
part 10:swap 交换二个 thread
对象
Description
It swaps the state of the object with that of x.
Declaration
Following is the declaration for std::thread::swap function.
void swap (thread& x) noexcept;
part 11:std::swap 特化 std::swap 算法
Description
It is used to exchanges the state of the thread objects x and y.
Declaration
Following is the declaration for std::thread::swap function.
void swap (thread& x, thread& y) noexcept;
Parameters
x,y − It is a thread objects.
实例:
//thread1.cpp 建立线程,并观察线程的并发执行与阻塞等待 #include <iostream> #include <thread> #include <chrono> using namespace std; void thread_function(int n) { std::thread::id this_id = std::this_thread::get_id(); //获取线程ID for(int i = 0; i < 5; i++){ cout << "Child function thread " << this_id<< " running : " << i+1 << endl; std::this_thread::sleep_for(std::chrono::seconds(n)); //进程睡眠n秒 } } class Thread_functor { public: // functor行为相似函数,C++中的仿函数是经过在类中重载()运算符实现,使你能够像使用函数同样来建立类的对象 void operator()(int n) { std::thread::id this_id = std::this_thread::get_id(); for(int i = 0; i < 5; i++){ cout << "Child functor thread " << this_id << " running: " << i+1 << endl; std::this_thread::sleep_for(std::chrono::seconds(n)); //进程睡眠n秒 } } }; int main() { thread mythread1(thread_function, 1); // 传递初始函数做为线程的参数 if(mythread1.joinable()) //判断是否能够成功使用join()或者detach(),返回true则能够,false则不可 mythread1.join(); // 使用join()函数阻塞主线程直至子线程执行完毕 Thread_functor thread_functor; //函数对象实例化一个对象 thread mythread2(thread_functor, 3); // 传递初始函数做为线程的参数 if(mythread2.joinable()) mythread2.detach(); // 使用detach()函数让子线程和主线程并行运行,主线程也再也不等待子线程 //lambda表达式格式:[capture list] (params list) mutable exception-> return type { function body } auto thread_lambda = [](int n){ std::thread::id this_id = std::this_thread::get_id(); for(int i = 0; i < 5; i++) { cout << "Child lambda thread " << this_id << " running: " << i+1 << endl; std::this_thread::sleep_for(std::chrono::seconds(n)); //进程睡眠n秒 } }; thread mythread3(thread_lambda, 4); // 传递初始函数做为线程的参数 if(mythread3.joinable()) mythread3.join(); // 使用join()函数阻塞主线程直至子线程执行完毕 std::thread::id this_id = std::this_thread::get_id(); for(int i = 0; i < 5; i++){ cout << "Main thread " << this_id << " running: " << i+1 << endl; std::this_thread::sleep_for(std::chrono::seconds(1)); } getchar(); return 0; }
线程建立的参数是函数对象,函数对象不止是函数指针或成员函数指针,同时还包括函数对象(仿函数)与lambda表达式。上面的代码分别用三种函数对象建立了三个线程**,其中第一个线程mythread1阻塞等待其执行完后继续往下执行**,第二个线程mythread2不阻塞等待在后台与后面的第三个线程mythread3并发执行,第三个线程继续阻塞等待其完成后再继续往下执行主线程任务。
为了便于观察并发过程,对三个线程均用了睡眠延时this_thread::sleep_for(duration)函数,且延时时间做为参数传递给该函数。这里的参数是支持C++泛型模板的,STL标准容器类型(好比Array/Vector/Deque/List/Set/Map/String等)均可以做为参数传递,但这里的参数默认是以拷贝的方式传递参数的,当指望传入一个引用时,要使用std::ref进行转换,实例见part 1中实例。
若是想要线程mythread2独立运行,修改以下
mythread2.detach(); ---》 mythread2.join();
线程mythread2和线程mythread3与主线程main 同步运行
mythread2.detach(); ---》 mythread2.join(); mythread3.join(); ---》 mythread3.detach();
小结:
当线程不须要相互依赖,不会产生数据竞争,或不是流水的实现思路下,用detach();
当可能产生数据竞争,数据之间相互依赖,算法实现设计为流水的状况下,使用join()函数,使其余线程进入阻塞状态。
针对任何线程(包括主线程),< thread > 还声明了一个命名空间std::this_thread,用以提升线程专属的全局函数。函数声明和效果见下表。 上面的代码就是利用了std::this_thread提供的函数得到当前线程的ID,让当前线程睡眠一段时间(通常须要< chrono >头文件提供duration或timepoint)的功能 。
参考资料: https://zh.cppreference.com/w/cpp/thread/thread https://www.tutorialspoint.com/cpp_standard_library https://blog.csdn.net/m0_37621078/article/details/104909834