C++11并发之std::thread<转>

时间:2022-12-16 09:57:39

最近技术上没什么大的收获,也是悲催的路过~

搞一点新东西压压惊吧!

C++11并发之std::thread

知识链接:
C++11 并发之std::atomic
 
本文概要:
1、成员类型和成员函数。
 
2、std::thread 构造函数。
3、异步。
4、多线程传递参数。
5、join、detach。
6、获取CPU核心个数。
7、CPP原子变量与线程安全。
8、lambda与多线程。
9、时间等待相关问题。
10、线程功能拓展。
11、多线程可变参数。
12、线程交换。
13、线程移动。
 
std::thread 在 #include<thread> 头文件中声明,因此使用 std::thread 时需要包含 #include<thread> 头文件。
 
1、成员类型和成员函数。
成员类型:
id
Thread id (public member type )                                       id
native_handle_type
Native handle type (public member type )

成员函数:

(constructor)
Construct thread (public member function )        构造函数
(destructor)
Thread destructor (public member function )      析构函数
operator=
Move-assign thread (public member function )  赋值重载
get_id
Get thread id (public member function )                获取线程id
joinable
Check if joinable (public member function )          判断线程是否可以加入等待
join
Join thread (public member function )                    加入等待
detach
Detach thread (public member function )              分离线程
swap
Swap threads (public member function )               线程交换
native_handle
Get native handle (public member function )       获取线程句柄
hardware_concurrency [static]
Detect hardware concurrency (public static member function )   检测硬件并发特性

Non-member overloads:

swap (thread)
Swap threads (function )
 
2、std::thread 构造函数。
如下表:
default (1)
thread() noexcept;
initialization(2)
template <class Fn, class... Args>   explicit thread (Fn&& fn, Args&&... args);
copy [deleted] (3)
thread (const thread&) = delete;
move [4]
hread (thread&& x) noexcept;
(1).默认构造函数,创建一个空的 thread 执行对象。
(2).初始化构造函数,创建一个 thread 对象,该 thread 对象可被 joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。
(3).拷贝构造函数(被禁用),意味着 thread 不可被拷贝构造。
(4).move 构造函数,move 构造函数,调用成功之后 x 不代表任何 thread 执行对象。
注意:可被 joinable 的 thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached。
 
std::thread 各种构造函数例子如下:
#include<thread>
#include<chrono>
using namespace std;
void fun1(int n) //初始化构造函数
{
cout << "Thread " << n << " executing\n";
n += ;
this_thread::sleep_for(chrono::milliseconds());
}
void fun2(int & n) //拷贝构造函数
{
cout << "Thread " << n << " executing\n";
n += ;
this_thread::sleep_for(chrono::milliseconds());
}
int main()
{
int n = ;
thread t1; //t1不是一个thread
thread t2(fun1, n + ); //按照值传递
t2.join();
cout << "n=" << n << '\n';
n = ;
thread t3(fun2, ref(n)); //引用
thread t4(move(t3)); //t4执行t3,t3不是thread
t4.join();
cout << "n=" << n << '\n';
return ;
}
运行结果:
Thread executing
n=
Thread executing
n=</span>
3、异步。
例如:
 
#include<thread>
using namespace std;
void show()
{
cout << "hello cplusplus!" << endl;
}
int main()
{
//栈上
thread t1(show); //根据函数初始化执行
thread t2(show);
thread t3(show);
//线程数组
thread th[]{thread(show), thread(show), thread(show)};
//堆上
thread *pt1(new thread(show));
thread *pt2(new thread(show));
thread *pt3(new thread(show));
//线程指针数组
thread *pth(new thread[]{thread(show), thread(show), thread(show)});
return ;
}
4、多线程传递参数。
例如:
#include<thread>
using namespace std;
void show(const char *str, const int id)
{
cout << "线程 " << id + << " :" << str << endl;
}
int main()
{
thread t1(show, "hello cplusplus!", );
thread t2(show, "你好,C++!", );
thread t3(show, "hello!", );
return ;
}
运行结果:
线程 1线程 :你好,C++!线程 :hello!
:hello cplusplus!
发现,线程 t1、t2、t3 都执行成功!
 
5、join、detach。
join例子如下:
#include<thread>
#include<array>
using namespace std;
void show()
{
cout << "hello cplusplus!" << endl;
}
int main()
{
array<thread, > threads = { thread(show), thread(show), thread(show) };
for (int i = ; i < ; i++)
{
cout << threads[i].joinable() << endl;//判断线程是否可以join
threads[i].join();//主线程等待当前线程执行完成再退出
}
return ;
}
运行结果:
hello cplusplus!
hello cplusplus! hello cplusplus!
总结:
join 是让当前主线程等待所有的子线程执行完,才能退出。
detach例子如下:
#include<thread>
using namespace std;
void show()
{
cout << "hello cplusplus!" << endl;
}
int main()
{
thread th(show);
//th.join();
th.detach();//脱离主线程的绑定,主线程挂了,子线程不报错,子线程执行完自动退出。
//detach以后,子线程会成为孤儿线程,线程之间将无法通信。
cout << th.joinable() << endl;
return ;
}
运行结果:
hello cplusplus!
结论:
线程 detach 脱离主线程的绑定,主线程挂了,子线程不报错,子线程执行完自动退出。
线程 detach以后,子线程会成为孤儿线程,线程之间将无法通信。
 
6、获取CPU核心个数。
例如:
#include<thread>
using namespace std;
int main()
{
auto n = thread::hardware_concurrency();//获取cpu核心个数
cout << n << endl;
return ;
}
运行结果:
结论:
通过  thread::hardware_concurrency() 获取 CPU 核心的个数。
 
7、CPP原子变量与线程安全。
问题例如:
#include<thread>
using namespace std;
const int N = ;
int num = ;
void run()
{
for (int i = ; i < N; i++)
{
num++;
}
}
int main()
{
clock_t start = clock();
thread t1(run);
thread t2(run);
t1.join();
t2.join();
clock_t end = clock();
cout << "num=" << num << ",用时 " << end - start << " ms" << endl;
return ;
}
运行结果:
num=,用时 ms
从上述代码执行的结果,发现结果并不是我们预计的200000000,这是由于线程之间发生冲突,从而导致结果不正确。
为了解决此问题,有以下方法:
(1)互斥量。
例如:
#include<thread>
#include<mutex>
using namespace std;
const int N = ;
int num();
mutex m;
void run()
{
for (int i = ; i < N; i++)
{
m.lock();
num++;
m.unlock();
}
}
int main()
{
clock_t start = clock();
thread t1(run);
thread t2(run);
t1.join();
t2.join();
clock_t end = clock();
cout << "num=" << num << ",用时 " << end - start << " ms" << endl;
return ;
}
运行结果:
num=,用时 ms
不难发现,通过互斥量后运算结果正确,但是计算速度很慢,原因主要是互斥量加解锁需要时间。
互斥量详细内容 请参考C++11 并发之std::mutex
(2)原子变量。
例如:
#include<thread>
#include<atomic>
using namespace std;
const int N = ;
atomic_int num{ };//不会发生线程冲突,线程安全
void run()
{
for (int i = ; i < N; i++)
{
num++;
}
}
int main()
{
clock_t start = clock();
thread t1(run);
thread t2(run);
t1.join();
t2.join();
clock_t end = clock();
cout << "num=" << num << ",用时 " << end - start << " ms" << endl;
return ;
}
运行结果:
num=,用时 ms
不难发现,通过原子变量后运算结果正确,计算速度一般。
原子变量详细内容 请参考C++11 并发之std::atomic。
(3)加入 join 。
例如:
#include<thread>
using namespace std;
const int N = ;
int num = ;
void run()
{
for (int i = ; i < N; i++)
{
num++;
}
}
int main()
{
clock_t start = clock();
thread t1(run);
t1.join();
thread t2(run);
t2.join();
clock_t end = clock();
cout << "num=" << num << ",用时 " << end - start << " ms" << endl;
return ;
}
运行结果:
num=,用时 ms
不难发现,通过原子变量后运算结果正确,计算速度也很理想。
 
8、lambda与多线程。
例如:
#include<thread>
using namespace std;
int main()
{
auto fun = [](const char *str) {cout << str << endl; };
thread t1(fun, "hello world!");
thread t2(fun, "hello beijing!");
return ;
}
运行结果:
hello world!
hello beijing!
9、时间等待相关问题。
例如:
#include<thread>
#include<chrono>
using namespace std;
int main()
{
thread th1([]()
{
//让线程等待3秒
this_thread::sleep_for(chrono::seconds());
//让cpu执行其他空闲的线程
this_thread::yield();
//线程id
cout << this_thread::get_id() << endl;
});
return ;
}
10、线程功能拓展。
例如:
#include<thread>
using namespace std;
class MyThread :public thread //继承thread
{
public:
//子类MyThread()继承thread()的构造函数
MyThread() : thread()
{
}
//MyThread()初始化构造函数
template<typename T, typename...Args>
MyThread(T&&func, Args&&...args) : thread(forward<T>(func), forward<Args>(args)...)
{
}
void showcmd(const char *str) //运行system
{
system(str);
}
};
int main()
{
MyThread th1([]()
{
cout << "hello" << endl;
});
th1.showcmd("calc"); //运行calc
//lambda
MyThread th2([](const char * str)
{
cout << "hello" << str << endl;
}, " this is MyThread");
th2.showcmd("notepad");//运行notepad
return ;
}
运行结果:
hello
//运行calc
hello this is MyThread
//运行notepad
11、多线程可变参数。
例如:
#include<thread>
#include<cstdarg>
using namespace std;
int show(const char *fun, ...)
{
va_list ap;//指针
va_start(ap, fun);//开始
vprintf(fun, ap);//调用
va_end(ap);
return ;
}
int main()
{
thread t1(show, "%s %d %c %f", "hello world!", , 'A', 3.14159);
return ;
}
运行结果:
hello world! A 3.14159
12、线程交换。
例如:
#include<thread>
using namespace std;
int main()
{
thread t1([]()
{
cout << "thread1" << endl;
});
thread t2([]()
{
cout << "thread2" << endl;
});
cout << "thread1' id is " << t1.get_id() << endl;
cout << "thread2' id is " << t2.get_id() << endl; cout << "swap after:" << endl;
swap(t1, t2);//线程交换
cout << "thread1' id is " << t1.get_id() << endl;
cout << "thread2' id is " << t2.get_id() << endl;
return ;
}
运行结果:
thread1
thread2
thread1' id is 4836
thread2' id is 4724
swap after:
thread1' id is 4724
thread2' id is 4836
两个线程通过 swap 进行交换。
 
13、线程移动。
例如:
#include<thread>
using namespace std;
int main()
{
thread t1([]()
{
cout << "thread1" << endl;
});
cout << "thread1' id is " << t1.get_id() << endl;
thread t2 = move(t1);;
cout << "thread2' id is " << t2.get_id() << endl;
return ;
}
运行结果:
thread1
thread1' id is 5620
thread2' id is 5620

从上述代码中,线程t2可以通过 move 移动 t1 来获取 t1 的全部属性,而 t1 却销毁了。

原贴地址:https://www.cnblogs.com/lidabo/p/7852033.html

C++11并发之std::thread<转>的更多相关文章

  1. c&plus;&plus;11并发之std&colon;&colon;thread

    知识链接: https://www.cnblogs.com/lidabo/p/7852033.html 构造函数如下: ) thread() noexcept; initialization() te ...

  2. C&plus;&plus;11 并发之std&colon;&colon;thread std&colon;&colon;mutex

    https://www.cnblogs.com/whlook/p/6573659.html (https://www.cnblogs.com/lidabo/p/7852033.html) C++:线程 ...

  3. C&plus;&plus;11并发之std&colon;&colon;mutex

    知识链接: C++11并发之std::thread   本文概要: 1. 头文件. 2.std::mutex. 3.std::recursive_mutex. 4.std::time_mutex. 5 ...

  4. C&plus;&plus;11 并发指南------std&colon;&colon;thread 详解

    参考: https://github.com/forhappy/Cplusplus-Concurrency-In-Practice/blob/master/zh/chapter3-Thread/Int ...

  5. C&plus;&plus;11并发——多线程std&colon;&colon;thread (一)

    https://www.cnblogs.com/haippy/p/3284540.html 与 C++11 多线程相关的头文件 C++11 新标准中引入了四个头文件来支持多线程编程,他们分别是< ...

  6. c&plus;&plus;11中关于std&colon;&colon;thread的join的思考

    c++中关于std::thread的join的思考 std::thread是c++11新引入的线程标准库,通过其可以方便的编写与平台无关的多线程程序,虽然对比针对平台来定制化多线程库会使性能达到最大, ...

  7. c&plus;&plus;11中关于&grave;std&colon;&colon;thread&grave;线程传参的思考

    关于std::thread线程传参的思考 最重要要记住的一点是:参数要拷贝到线程独立内存中,不管是普通类型.还是引用类型. 对于传递参数是引用类型,需要注意: 1.当指向动态变量的指针(char *) ...

  8. C&plus;&plus; 11 笔记 (五) : std&colon;&colon;thread

    这真是一个巨大的话题.我猜记录完善绝B需要一本书的容量. 所以..我只是略有了解,等以后用的深入了再慢慢补充吧. C++写多线程真是一个痛苦的事情,当初用过C语言的CreateThread,见过boo ...

  9. Cocos2dx 3&period;0 过渡篇(二十六)C&plus;&plus;11多线程std&colon;&colon;thread的简单使用&lpar;上&rpar;

    昨天练车时有一MM与我交替着练,聊了几句话就多了起来,我对她说:"看到前面那俩教练没?老色鬼两枚!整天调戏女学员."她说:"还好啦,这毕竟是他们的乐趣所在,你不认为教练每 ...

随机推荐

  1. backup log is terminating abnormally because for write on file failed&colon; 112&lpar;error not found&rpar;

    昨天遇到一个案例,YourSQLDba做事务日志备份时失败,检查YourSQLDba输出的错误信息如下: <Exec> <ctx>yMaint.backups</ctx& ...

  2. 未能加载文件或程序集&OpenCurlyDoubleQuote;DeveloperKit10&period;1&sol;DotNet&sol;ESRI&period;ArcGIS&period;ADF&period;Local&period;或它的某一个依赖项

    使用VS2010进行ArcGIS Engine 10.1进行开发过程中,出现: 错误 1 未能加载文件或程序集“file:///D:/ArcGIS/DeveloperKit10.0/DotNet/ES ...

  3. struts2&plus;ajax实现异步验证实现

    由于老师布置作业的需要,在添加管理员的时候,要实现验证添加的管理员的用户名是否在数据库中已经存在,然后再客户端给用户一个提示.我首先想到的就是利用ajax实现异步验证技术,由于利用的ssh框架,所以在 ...

  4. 你知道如何为iOS工程改名吗?

    我们在iOS开发中,难免会遇到项目做到一半要改名字的情况.如果项目名差的太大,工程名看起来总是不舒服的,有良心的开发者可能就会想着为工程改个贴切的名字,那么你就为用到本文记录的内容. 如果我们开发的两 ...

  5. 网络编程第六讲Select模型

    网络模型第六讲Select模型 一丶Select模型是什么 以前我们讲过一个迭代模型.就是只服务一个客户端连接.但是实际网络编程中.复杂的很多. 比如一个 C/S架构程序 (客户端/服务端) 客户端很 ...

  6. Github之协同开发

    一.协同开发 1.引子:假如三个人共同开发同一份代码,每个人都各自安排了任务,当每个人都完成了一半的时候,提交不提交呢? 要提交,提交到dev吗,都上传了一半,这样回家拿出来的代码根本跑不起来.所以, ...

  7. mysql之 slow log 慢查询日志

    一. 相关参数: • slow_query_log ◦ 是否开启慢查询日志 • slow_query_log_file ◦ 慢查询日志文件名, 在 my.cnf 我们已经定义为slow.log,默认是 ...

  8. JavaScript学习总结&lpar;三&rpar;——闭包、IIFE、原型、函数与对象

    一.闭包(Closure) 1.1.闭包相关的问题 请在页面中放10个div,每个div中放入字母a-j,当点击每一个div时显示索引号,如第1个div显示0,第10个显示9:方法:找到所有的div, ...

  9. BZOJ3811 玛里苟斯(线性基&plus;概率期望)

    k=1的话非常好做,每个有1的位都有一半可能性提供贡献.由组合数的一些性质非常容易证明. k=2的话,平方的式子展开可以发现要计算的是每一对位提供的贡献,于是需要计算每一对位被同时选中的概率.找出所有 ...

  10. Springboot热部署(热部署原理)和用IDEA开发需要的配置

    热部署原理 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>s ...