一个程序至少有一个正在执行的main()函数的线程,其他线程与主线程同时运行
创建线程的方式有很多,可以使用C风格的调用pthread线程库函数实现,但是C++标准中定义了thread相关接口,底层依赖动态库pthread但是这使得不同平台上的C++多线程代码能够得到统一的规范,使得代码的平台可移植性大大提高
//example1.cpp
#include<thread>
#include<iostream>
using namespace std;
void hello(){
<< "hello world" << endl;
cout }
int main(int argc,char**argv){
(hello);
thread process.join();//等待线程process运行结束
processreturn 0;
}
//g++ example1.cpp -o example1.exe -lpthread && ./example1.exe
//example2.cpp
#include<thread>
#include<iostream>
using namespace std;
//使用函数对象忘记的话就要复习C++基础知识喽
class Hello{
public:
void operator()() const{
<< "hello world"<<endl;
cout }
};
int main(int argc,char**argv){
;
Hello hello//thread process(hello);//正确
//thread process(Hello()); //error 相当于声明了Hello()函数,并不是创建了一个Hello对象
//thread process((Hello()));//正确
{Hello()};//正确 使用初始化列表
thread process.join();//等待线程运行结束
processreturn 0;
}
//g++ example2.cpp -o example2.exe -lpthread && ./example2.exe
总之我们就是为线程的构造函数传递一个function对象例如接收function<int(int,int)>
,function类型在标准库functional头文件中
如果忘记了请看C++的第14章,Lambda表达式是C++11中新增的特性
//example3.cpp
#include <iostream>
#include <thread>
using namespace std;
int main(int argc, char **argv)
{
//传递lambda表达式
m_thread([]() -> void
thread { cout << "hello thread" << endl; });
m_thread.join(); // hello thread
return 0;
}
// g++ ./example3.cpp -o example.exe -lpthread & ./example.exe
主要体现在一个函数已经返回,而线程使用其内部的局部变量,函数已经返回,但是线程没有结束,仍旧尝试访问函数局部资源
//example4.cpp
#include <iostream>
#include <thread>
using namespace std;
void func()
{
int i = 999;
([&i]() -> void
thread process{
while(i>0){
<< --i << endl;
cout } });
.detach(); //不等待线程结束
process};
int main(int argc, char **argv)
{
();
func//结果并不会按照我们理想中的情形
//从999...0 因为中途i的内存资源被释放掉了
return 0;
}
// g++ ./example4.cpp -o example.exe -lpthread & ./example.exe
如果要等待线程完成,则需要调用join()方法,一旦使用过join后,其joinable()将会返回false
//example5.cpp
#include <iostream>
#include <thread>
using namespace std;
int main(int argc, char **argv)
{
m_thread([]() -> void
thread { cout << "hello world" << endl; });
if (m_thread.joinable())
{
m_thread.join();
}
<< "joined" << endl;
cout // joined一定在hello world之后
return 0;
}
当主线程因为某种原因结束时,但是子线程还处于运行状态,则将会子线程分离出去保持运行,往往父线程出现错误终止时,要对子线程做出控制
//example6.cpp
#include <iostream>
#include <thread>
using namespace std;
void func()
{
throw runtime_error("error");
}
int main(int argc, char **argv)
{
int i = 999;
m_thread([&i]() -> void
thread {
while(i){
<< --i << endl;
cout } });
try
{
();
func//即使func出错也会等到m_thread运行结束后结束程序
//否则i的内存释放导致子线程运作不正常
}
catch (runtime_error e)
{
<< e.what() << endl;
cout m_thread.join(); //等待子线程运行结束
throw runtime_error("exit"); //异常结束父线程
}
m_thread.join(); //正常等待
return 0;
}
// g++ ./example6.cpp -o example.exe -lpthread & ./example.exe
//example7.cpp
#include <iostream>
#include <thread>
using namespace std;
class thread_guard
{
private:
std::thread &t;
public:
// explicit禁止用thread赋值给thread_guard
explicit thread_guard(std::thread &t) : t(t) {}
~thread_guard() //当对象被销毁时调用
{
<< "~thread_guard\n"
cout << flush;
if (t.joinable())
.join();
t}
//禁止合成构造拷贝
(const thread_guard &) = delete;
thread_guard//禁止合成赋值拷贝
&operator=(const thread_guard &) = delete;
thread_guard };
int main(int argc, char **argv)
{
{
int i = 999;
m_thread([&i]() -> void
thread { while(i)cout<<--i<<endl; });
(m_thread);
thread_guard guard//这使得i的声明周期与guard声明周期是一样的
//在i将会销毁时guard也会被销毁
//进而触发guard析构函数内的join等待m_thread使用i完毕
}
return 0;
}
使用detach()使得线程在后台运行,使得线程分离,不再有thread对象引用它,不再可控,但C++运行库保证,在线程退出时,相关的资源能够正常的回收
分离线程通常称为守护线程(daemon threads)
,一旦std::thread调用detach则对象本身不再与实际执行的线程有关系,且这个线程无法汇入(再次获得控制)
只能对正在运行的线程使用detach也即是joinable()返回true
//example8.cpp
#include <iostream>
#include <thread>
#include <unistd.h>
#include <fstream>
using namespace std;
int main(int argc, char **argv)
{
([](){
thread f_threadint i = 1000;
// i为值捕获
m_thread([i]() mutable -> void
thread {
("temp.iofile",fstream::app|fstream::in);
ofstream oswhile(i>0){
<< --i << endl;
cout << to_string(i) << endl;
os }
.close();
os<< "close file" << endl;
cout });
if (m_thread.joinable())
{
m_thread.detach(); //分离线程
}
<< m_thread.joinable() << endl; // 0 线程分离后与m_thread对象再无关系
cout });
.detach();
f_thread(5);//主进程线程睡眠5秒,否则进程结束全部线程停止
sleep<< "end" << endl;
cout //当父线程f_thread运行结束时 m_thread产生的线程并不会结束
//但是当主进程结束时,其所有线程将会被结束
return 0;
}
对于WINDOWS系统,主线程退出,其他未执行完毕的子线程也会退出,因为主线程退出调用exit(),相当于终止整个进程,其他线程自然而然会终止; 对于linux系统,主线程退出,其他未执行完毕的子线程不会退出,会继续执行,但是这个进程会编程僵尸进程,通过ps -ef查看进程列表,如果有defunct字样的进程,就是僵尸进程。僵尸进程应该被避免。所以,我们应该在主线程退出之前等待其他子线程执行完毕
1、父线程是主线程,则父线程退出后, 子线程一定会退出。
2、父线程不是主线程,则父线程退出后, 子线程不受影响,继续运行。
总之进程的mian线程会随着主进程结束而结束,主进程结束程序的所有进程都会被干掉,但是子线程开的子线程就不同
#include<iostream>
#include<thread>
#include<string>
using namespace std;
void f(int t,const string&s) {
<< t << " " << s << endl;
cout }
int main() {
(::f,1,"hello");
thread t1.join();//1 hello
t1
char buffer[1024];
int i=999;
(buffer, "%i",i);
sprintf_s(f,1,buffer);//参数自动转换
thread t2.join();//1 999
t2return 0;
}
#include<iostream>
#include<thread>
#include<string>
using namespace std;
void f(int t,const string&s) {
<< t << " " << s << endl;
cout }
int main() {
char buffer[1024];
int i=999;
(buffer, "%i",i);
sprintf_s(f,1,buffer);//参数自动转换
thread t2.detach();
t2//在main结束时可能t2还没有利用buffer指针构造string
//可能会造成悬空指针的问题
//应该使用
//std::thread t2(f,1,std::string(buffer));
//在传递到构造函数之前,将字面值转化为string
return 0;
}
怎样传递引用类型参数,因为thread的构造函数机制与std::bind类似,所以其绑定的参数是拷贝而不是引用,在语言基础泛型算法的bind引用参数部分学习过,以及std::ref的使用
#include<iostream>
#include<thread>
#include<string>
using namespace std;
void func(int&i) {
++i;
}
int main() {
int i = 99;
/*thread t(::func,i);
t.join();
cout << i << endl;*/
//报错,thread的构造函数并不知道函数的参数类型
//只是盲目的拷贝提供的变量
//想要解决此问题就要使用ref
(::func,std::ref(i));
thread t.join();
t<< i << endl;//100
cout return 0;
}
可以提供一个成员函数指针,并提供一个其类型对象的地址
#include<iostream>
#include<thread>
#include<string>
#include<functional>
using namespace std;
class X {
public:
void exe(int num);
};
void X::exe(int num) {
<< num << endl;
cout }
int main() {
m_x;
X int num = 100;
std::thread t(&X::exe, &m_x,num);
.join();//100
t
<void(int)> m_f = std::bind(&X::exe, &m_x, num);
functionm_f(num);//100
return 0;
}
#include<iostream>
#include<thread>
#include<functional>
#include<memory>
using namespace std;
void func(unique_ptr<int>ptr) {
<< *ptr << endl;
cout }
void funcb(shared_ptr<int>ptr) {
<<*ptr<<endl;
cout}
int main() {
<int>ptr(new int(1));
unique_ptr(::func,std::move(ptr));
thread t.join();
t//cout << *ptr << endl; ptr已经不再指向申请的内存,因为已经移交给了形参
if (nullptr==ptr) {
<< "is nullptr" << endl;
cout }
//1
//is nullptr
<int>ptrb(new int(100));
shared_ptr(::funcb,std::move(ptrb));
thread t1.join();//100
t1<<boolalpha<< (ptrb == nullptr) << endl;//true
cout
//其过程是将ptrb所指的int对象,通过
//将ptrb所指对象作为右值传递给int的移动构造器函数或移动赋值运算符
//然后进行了内容拷贝
return 0;
}
std::thread是不能进行赋值的,但是可以在std::thread没有绑定任务或者已经结束是使用std::move令其关联新的线程任务
#include<iostream>
#include<thread>
#include<functional>
#include<memory>
using namespace std;
void funca() {
for(int i=0;i<10;i++)
<< i << endl;
cout }
void funcb() {
}
int main() {
(::funca);
thread t1//std::move返回一个右值引用常量表达式
= std::move(t1);//t1背后的任务将由t2管理
thread t2 <<boolalpha<< t1.joinable()<<noboolalpha<< endl;//false
cout << boolalpha << t2.joinable() << noboolalpha << endl;//true
cout .join();
t2<< "executed funca" << endl;
cout
//如果thread左值已经关联一个线程,则不能修改其关联
(::funca);
thread t3//t3.join();//等待t3关联线程结束后,可以让其关联新的其他线程任务
= std::move(t2);//t3没结束前赋值会发生错误
t3 return 0;
}
#include<iostream>
#include<thread>
#include<functional>
#include<memory>
using namespace std;
void funcb() {
<< "funcb" << endl;
cout }
//thread作为函数参数
void func(thread t) {
.join();
t}
//函数返回thread对象
() {
thread backreturn thread(funcb);//允许
}
//函数返回thread对象
() {
thread backb(funcb);
thread tbool res=t.joinable();
return t;
}
int main() {
(thread(funcb));//funcb
func(funcb);
thread t//func(t);//不允许 禁止thread拷贝
//使用std::move可以解决
(std::move(t));//funcb
func
=back();
thread t1.join();//funcb
t1
=backb();
thread t2.join();//funcb
t2return 0;
}
#include<iostream>
#include<thread>
#include<functional>
#include<memory>
using namespace std;
void funcb() {
<< "funcb" << endl;
cout }
void func(thread &t) {
<< boolalpha << t.joinable() << noboolalpha << endl;//true
cout .join();
t}
int main() {
(funcb);
thread t(t);
funcreturn 0;
}
#include<iostream>
#include<thread>
#include<functional>
#include<memory>
using namespace std;
//基于转移所有权的作用域自动join
class scoped_thread {
private:
std::thread t;
public:
explicit scoped_thread(std::thread t_) :t(std::move(t_)) {
if (!t.joinable()) {
throw std::logic_error("no thread");
}
}
~scoped_thread() {
.join();
t}
(const scoped_thread&) = delete;//禁止拷贝
scoped_thread& operator=(const scoped_thread&) = delete;//禁止拷贝
scoped_thread};
int main() {
{
auto func = []()->void {
<< "hello world" << endl;
cout };
(func);
thread t(std::move(t));
scoped_thread scoped}
<< "end" << endl;
cout return 0;
}
/*
hello world
end
*/
#include<iostream>
#include<thread>
#include<functional>
#include<memory>
#include<string>
using namespace std;
//joining_thread
class joining_thread {
private:
std::thread t;
public:
()noexcept = default;
joining_threadtemplate<typename Callable,typename ...Args>
explicit joining_thread(Callable&& func, Args&&...args):t(func,std::forward<Args>(args)...) {
}
explicit joining_thread(std::thread t_)noexcept :t(std::move(t_)) {
}
(joining_thread&& other)noexcept:t(std::move(other.t)) {
joining_thread
}
& operator=(joining_thread&& other)noexcept {
joining_threadif (joinable()) {
();
join}
= std::move(other.t);
t return*this;
}
bool joinable()const noexcept {
return t.joinable();
}
void join() {
if(joinable())
.join();
t}
~joining_thread()noexcept {
if (joinable())
();
join}
void swap(joining_thread&other)noexcept {
.swap(other.t);
t}
std::thread::id get_id()const noexcept {
return t.get_id();
}
void detach() {
.detach();
t}
std::thread& as_thread()noexcept {
return t;
}
const std::thread& as_thread()const noexcept {
return t;
}
};
int main() {
([]()->void {
joining_thread t<< "hello world" << endl;
cout });//hello world
return 0;
}
#include<iostream>
#include<thread>
#include<vector>
#include<functional>
using namespace std;
int main() {
<void(int)> func = [](int n)->void {
function<< n << endl;
cout };
<thread>vec;
vectorfor (int i = 0; i < 10; i++) {
.emplace_back(func,i);
vec}
for (thread& t : vec) {
.join();
t}
return 0;
}
std::thread::hardware_concurrency()返回值可以是CPU核心数量,返回值仅仅是一个标识,无法获取时返回0
#include<iostream>
#include<thread>
#include<vector>
#include<functional>
using namespace std;
int main() {
<< std::thread::hardware_concurrency() << endl;// It's 12 on my host
cout return 0;
}
/*
并发版的std::accumulate
*/
#include<iostream>
#include<thread>
#include<vector>
#include<functional>
#include<numeric>
using namespace std;
template<typename Iterator,typename T>
void accumulate_block(Iterator first, Iterator end, T& t) {
= std::accumulate(first, end, t);
t }
template<typename Iterator,typename T>
(Iterator first, Iterator last, T init) {
T parallel_accumulateconst unsigned long length = std::distance(first,last);//计算求和列表长度
if (!length) {//长度为0
return init;
}
//每个线程最小负责的长度
const unsigned long min_per_thread = 25;
//理应需要的线程数量 当length>=1时
const unsigned long max_threads = (length + min_per_thread - 1) / min_per_thread;
//CPU核心
unsigned long const hardware_threads =std::thread::hardware_concurrency();
//得出合理的线程数量
unsigned long const num_threads = std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads);
//每个block的元素数量
unsigned long const block_size = length / num_threads;
//记录计算内容
std::vector<T> results(num_threads);
std::vector<std::thread> threads(num_threads - 1);
= first;
Iterator block_start for (unsigned long i = 0; i < (num_threads - 1); ++i)
{
= block_start;
Iterator block_end std::advance(block_end, block_size);//移动迭代器
[i] = std::thread(
threads<Iterator,T>,
accumulate_block, block_end, std::ref(results[i]));
block_start= block_end;
block_start }
(block_start, last, results[num_threads - 1]);//剩余的部分
accumulate_blockfor (auto& entry : threads)//等待全部子任务结束
.join();
entryreturn std::accumulate(results.begin(), results.end(), init);
}
int main() {
<int>vec;
vectorfor (int i = 0; i < 100; i++) {
.push_back(i);
vec}
long sum = 0;
=parallel_accumulate(vec.begin(),vec.end(),sum);
sum<< sum << endl;//4950
cout return 0;
}
每个线程任务由自己的ID标识
std::this_thread::get_id()以及thread.get__id()的使用
#include<iostream>
#include<thread>
#include<vector>
#include<functional>
#include<numeric>
#include<Windows.h>
using namespace std;
int main() {
([]()->void {
thread t1<< std::this_thread::get_id() << endl;//a
cout });
<< t1.get_id() << endl;//a
cout .join();
t1([]()->void {
thread t2<< std::this_thread::get_id() << endl;//b
cout });
<< t2.get_id() << endl;//b
cout .join();
t2<< std::this_thread::get_id() << endl;//c
cout
//std::hash<std::thread::id> 容器, std::thread::id 也可以作为无序容器的键值。
std::hash<std::thread::id> t;
<< t(this_thread::get_id()) << endl;
cout
//std::thread::id 允许赋值 比较对比等操作
//当thread出于未关联 以及detached状态时 get_id返回值为0
return 0;
}