在C中已经有一个叫做pthread的东西来进行多线程编程,但是并不好用 ,所以c++11标准库中出现了一个叫作std::thread的东西。
std::thread常用成员函数
构造&析构函数
常用成员函数
例一:thread的基本使用
#include <iostream>
#include <thread>
using namespace std;
void doit() {
for(int i=0;i<10;i++){
cout << "World!" << endl;
}
}
int main() {
thread a([]() {
for(int i=0;i<10;i++){
cout << "Hello " << flush;
}
});
thread b(doit);
a.join();
b.join();
return 0;
}
输出结果:
Hello, World!
或者是
World!
Hello,
那么,为什么会有不同的结果呢?
这就是多线程的特色!
多线程运行时是以异步方式执行的,与我们平时写的同步方式不同。异步方式可以同时执行多条语句。
在上面的例子中,我们定义了2个thread,这2个thread在执行时并不会按照一定的顺序。打个比方,2个thread执行时,就好比赛跑,谁先跑到终点,谁就先执行完毕。
例二:thread执行有参数的函数
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
void countNumber(int id, unsigned int n) {
this_thread::sleep_for(chrono::seconds(10));
cout << "Thread " << id <<"'s val is "<<n
<<". And it's finished!" << endl;
}
int main() {
thread th[10];
for (int i = 0; i < 10; i++)
th[i] = thread(countNumber, i, 10000);
for (int i = 0; i < 10; i++)
th[i].join();
return 0;
}
这个例子中我们在创建线程时向函数传递了一些参数,但如果要传递引用参数呢?是不是像这个例子中直接传递就行了?其实不行,因为thread在传递参数时,是以右值传递的。
那么我们该如何传递一个左值呢?std::ref和std::cref很好地解决了这个问题。
std::ref 可以包装按引用传递的值。
std::cref 可以包装按const引用传递的值。
例三:thread执行带有引用参数的函数
#include <iostream>
#include <thread>
using namespace std;
template <typename T>
void changeValue(T& x,T val){
x=val;
}
int main(){
cout<<"---------before------------"<<endl;
thread th[100];
int nums[100]{0};
for(auto& x:nums)
cout<<x<<" ";
for (int i = 0; i < 100; i++)
th[i] = thread(changeValue<int>, ref(nums[i]), i+1);
cout<<endl<<"---------after------------"<<endl;
for (auto& t : th)
t.join();
for(auto& x:nums)
cout<<x<<" ";
cout<<endl;
return 0;
}
例四:thread启动类的成员函数
基本语法
std::thread t(&ClassName::MemberFunction, objectPointer, args...);
其中:
&ClassName::MemberFunction 是成员函数的指针。
objectPointer 是指向类实例的指针或引用,指明成员函数在哪个对象上执行。
args… 是传递给成员函数的参数。
#include <iostream>
#include <thread>
using namespace std;
class Count{
public:
Count():m_count(0){}
void increment(int numInterations){
for(int i=0;i<numInterations;i++)
m_count++;
}
int getCount(){
return m_count;
}
private:
int m_count;
};
int main(){
const int numIterations=100;
Count count;
thread th(&Count::increment,&count,numIterations);
th.join();
cout<<count.getCount()<<endl;
return 0;
}
注意事项
线程是在thread对象被定义的时候开始执行的,而不是在调用join函数时才执行的,调用join函数只是阻塞等待线程结束并回收资源。
分离的线程(执行过detach的线程)会在调用它的线程结束或自己结束时释放资源。
线程会在函数运行完毕后自动释放,不推荐利用其他方法强制结束线程,可能会因资源未释放而导致内存泄漏。
没有执行join或detach的线程在程序结束时会引发异常。