C++ 线程管理
上一节我们回顾了一下线程的基础概念,从这一节开始我们通过简短的程序片段来一起学习c++线程基础编程,以下程序片段都基于c++11编写。
- 第一步:创建线程
#include<thread>
#include<iostream>
using namespace std;
/**
线程的工作函数:print_hello
功能很简单,只是打印一行字符串
*/
void print_hello()
{
cout<<"hello thread!"<<endl;
}
public static void main(args)
{
//线程对象 t1
thread t1(print_hello);
//等待线程结束
t1.join();
}
上面的代码中我们通过c++关键字thread,创建了一个线程对象t1,并且给t1关联了一个执行函数print_hello,每一个线程都有一个执行函数,负责线程的具体执行工作。
t1.join表示等待线程结束,至此我们成功创建了第一个线程,但是这个线程的工作很简单,只是打印出一行问候语就结束了,接下来我们看第二个问题,如何给线程传递参数?
- 第二步:给线程传递参数
#include<thread>
#include<iostream>
using namespace std;
/**
线程的工作函数:print_hello
功能很简单,只是打印一行字符串,带一个参数
*/
void print_hello(string msg)
{
cout<<msg<<endl;
}
public static void main(args)
{
string message = "hello thread params";
//线程对象 t1
thread t1(print_hello,message);
//等待线程结束
t1.join();
}
通常情况下我们可能需要传递一些参数到线程中,上面的例子中,我们的线程函数是一个带参数的函数,我们要给这个函数传递参数进去,只需要构造t1对象的时候,把参数放在函数名的右边传过去就可以了,当然这是最简单的参数传递情况,下面我们接着看一些复杂参数的情况:
- 传递引用
#include<thread>
#include<iostream>
using namespace std;
/**
线程的工作函数:print_hello
功能很简单,只是打印一行字符串,带一个参数
*/
void print_hello(string& msg)
{
cout<<msg<<endl;
}
public static void main(args)
{
string message = "hello thread params";
//线程对象 t1
thread t1(print_hello,std::ref(message));
//等待线程结束
t1.join();
}
上面的代码中,线程函数的参数期望是一个string类型的引用,我们通过std::ref将message转换为引用传递到线程中去。
- 传递指针
#include<thread>
#include<iostream>
using namespace std;
void sum(int* n)
{
*n++;
}
public static void main(args)
{
int n = 100;
//线程对象 t1
thread t1(print_hello,&n);
//等待线程结束
t1.join();
cout<<"n="<<n<<endl;
}
这个例子中,我们传递了n的地址到线程里面,然后在线程里面对n进行++操作,最后在线程结束后输出n的值。
- 多个参数传递
#include<thread>
#include<iostream>
using namespace std;
//多个参数的函数
void sum(int n,string msg)
{
*n++;
cout<<msg<<endl;
}
public static void main(args)
{
int n = 100;
string message = "hello";
//线程对象 t1
thread t1(print_hello,&n,message);
//等待线程结束
t1.join();
cout<<"n="<<n<<endl;
}
只需要在函数名的右边依次传递函数参数即可。
- 传递对象参数,执行对象的成员方法
#include<thread>
#include<iostream>
using namespace std;
class MyJob{
public:
void do_work(string msg);
};
MyJob my_job;
public static void main(args)
{
std::thread t(&MyJob::do_work,&my_job,"hello");
t.join();
}
上面的事例中,把my_job对象的do_work作为线程函数传递给线程对象t。
- 线程分离
#include<thread>
#include<iostream>
using namespace std;
//多个参数的函数
void sum(int n,string msg)
{
*n++;
cout<<msg<<endl;
}
public static void main(args)
{
int n = 100;
string message = "hello";
//线程对象 t1
thread t1(print_hello,&n,message);
//分离线程
t1.detach();
}
线程一旦通过detach分离后,就与thread对象无关了,成为了后台线程。
- 创建多个线程
//线程函数
void do_work(unsigned id);
//产生线程的函数
void produce_threads()
{
std::vector<std::thread> threads;
for(unsigned i=0; i < 20; ++i)
{
threads.push_back(std::thread(do_work,i)); // 产生线程
}
std::for_each(threads.begin(),threads.end(),
std::mem_fn(&std::thread::join)); // 对每个线程调用join()
}
上面的代码片段产生了20个线程,并且等待20个线程结束。
- 销毁线程
当我们创建了线程以后,一般情况下,我们需要等待线程函数执行结束,一旦线程函数执行结束,那么线程也就自然销毁了,除非有必要我们不会强制结束线程,thread对象在析构的时候会调用std::terminate()销毁资源。