文章目录
一、创建线程
1、创建线程
线程是通过构造
std::thread
对象来开始的,该对象指定了线程上要运行的任务,std::thread
可以与任何可调用类型一起工作,创建线程的基本语法如下:
#include <thread>
std::thread t(function_name, args...)
创建线程使用的可调用实体如下:
- 全局函数
- lambda表达式
- 函数对象
- 静态成员函数
- 非静态成员函数
示例:
#include <iostream>
#include <thread>
using namespace std;
void Work()
{
cout << "hello world" << endl;
}
int main()
{
std::thread myThread(Work);
myThread.join(); // 阻塞等待线程执行完成
return 0;
}
2、传递参数给线程
传递参数给可调用对象或函数,基本上就是简单地将额外的参数传递给
std::thread
构造函数。但重要的是,参数会以值拷贝的方式被复制到内部存储空间,在那里新创建的执行线程可以访问他们。
2.1、传入普通参数
示例:
#include <iostream>
#include <thread>
using namespace std;
void Display(int a, string str)
{
cout << "a = " << a << ", str = " << str << endl;
}
int main()
{
std::thread t(Display, 10, "hello world");
t.join();
return 0;
}
2.2、传入引用
示例:
#include <iostream>
#include <thread>
using namespace std;
struct Point
{
int x;
int y;
};
void Modify(Point &p)
{
p.x = 100;
p.y = 100;
}
int main()
{
Point p{66, 66};
cout << "before modify p.x = " << p.x << "; p.y = " << p.y << endl;
// 使用 std::ref 传递引用类型给线程函数
std::thread t(Modify, ref(p));
t.join();
cout << "after modify p.x = " << p.x << "; p.y = " << p.y << endl;
return 0;
}
2.3、传入类的成员函数指针
示例:
#include <iostream>
#include <thread>
using namespace std;
class MyClass
{
public:
void Display(int x)
{
cout << "x = " << x << endl;
}
};
int main()
{
MyClass obj;
// 类的成员函数做为线程函数入口,需要把对象地址传进去
std::thread t(MyClass::Display, &obj, 20);
t.join();
return 0;
}
二、join与detach
2.1、join
join()
函数的作用是让主线程等待该子线程完成,然后主线程再继续执行。这种情况下,子线程可以安全的访问主线程中的资源。子线程结束后由主线程负责回收子线程资源,示例:
#include <iostream>
#include <thread>
using namespace std;
void Display()
{
cout << "hello world";
}
int main()
{
std::thread t(Display);
// 阻塞等子线程执行完成,再执行主线程操作
t.join();
return 0;
}
2.2、detach
detach()
称为分离线程函数,使用detach()
函数会让线程在后台运行,即主线程不会等待子线程运行结束才结束,通常称分离线程为守护线程(daemon threads)。UNIX中守护线程是指,没有任何显式的用户接口,并在后台运行的线程,这种线程的特点就是长时间运行,示例:
#include <iostream>
#include <thread>
#include <unistd.h>
using namespace std;
void Display()
{
while (true)
{
cout << "hello world";
sleep(1);
}
}
int main()
{
std::thread t(Display);
// 线程分离
t.detach();
return 0;
}
2.3、joinable
一个线程对象要么被
join()
,要么被detach()
,如果两者都无,那么线程对象在析构时调用std::terminate
使得程序异常结束。一个子线程只能调用join()
和detach()
中的一个,且只允许调用一次。可以调用joinable()
来判断是否可以成功调用join()
或detach()
。