01
引言
std::thread 是C++11标准引入的一个轻量级线程库,它提供了创建和管理线程的能力,方便用户创建新的线程,并执行指定的函数。
02
使用方法
std::thread 使用很方便,以下是一个简单的示例代码:
#include
#include
void myTask(int id) {
std::cout << "Thread " << id << " is running" << std::endl;
}
int main() {
std::thread t1(myTask, 1); // 创建一个新线程 t1,执行 myTask 函数,并传递参数 1
std::thread t2(myTask, 2); // 创建一个新线程 t2,执行 myTask 函数,并传递参数 2
std::cout << "Main Thread is running" << std::endl;
t1.join(); // 等待线程 t1 执行完毕
t2.join(); // 等待线程 t2 执行完毕
std::cout << "All threads are finished" << std::endl;
return 0;
}
results:
Main Thread is running
Thread 1 is running
Thread 2 is running
All threads are finished
03
std::thread 线程创建方法
在 C++ 中,使用标准库的 std::thread 类可以创建和管理线程。以下是创建线程的基本步骤:
定义线程函数:首先需要定义一个函数,作为线程的入口点。该函数将在新线程中执行。例如:
void myThreadFunction() {
// 在这里编写线程的逻辑代码
}
创建线程对象并启动线程:使用 std::thread 类创建线程对象,并将线程函数作为参数传递给构造函数。然后,使用线程对象的 join 或 detach 方法。
int main() {
// 创建线程对象并启动线程
std::thread myThread(myThreadFunction);
// 执行其他主线程的操作
// 等待线程结束并回收资源
myThread.join();
return 0;
}
除了 join 方法外,还可以使用 detach 方法分离线程。使用 detach 后,线程将在后台运行,且不能再通过 join 方法等待其结束。这在某些情况下可能会有用,但需要确保线程的资源能够正确管理和释放。
04
std::thread 线程函数参数
在创建 std::thread 对象时,可以向其构造函数传递线程函数的参数。有几种方式可以传递参数:
使用函数指针或成员函数指针:如果线程函数是一个全局函数、静态成员函数或非静态成员函数,可以直接将函数指针或成员函数指针作为参数传递给 std::thread 构造函数。例如:
void myThreadFunction(int arg1, double arg2) {
// 在线程函数中使用传递的参数
// TODO: 线程逻辑代码
}
class MyClass {
public:
void myMemberThreadFunction(int arg1, double arg2) {
// 在成员线程函数中使用传递的参数
// TODO: 线程逻辑代码
}
};
int main() {
int arg1 = 42;
double arg2 = 3.14;
std::thread myThread(myThreadFunction, arg1, arg2);
MyClass obj;
std::thread memberThread(&MyClass::myMemberThreadFunction, &obj, arg1, arg2);
// 执行其他主线程的操作
myThread.join();
memberThread.join();
return 0;
}
2. 使用 lambda 表达式:可以使用 lambda 表达式捕获并传递参数。例如:
int main() {
int arg1 = 42;
double arg2 = 3.14;
std::thread myThread([&arg1, arg2]() {
// 在线程函数中使用捕获的参数
// TODO: 线程逻辑代码
});
// 执行其他主线程的操作
myThread.join();
return 0;
}
lambda 表达式 [&arg1, arg2] 捕获了外部变量 arg1,并通过值传递方式传递了 arg2,然后将 lambda 表达式作为线程函数传递给 std::thread 构造函数。
3. 无论是使用函数指针、成员函数指针还是 lambda 表达式,都可以在创建 std::thread 对象时传递线程函数的参数。这样可以灵活地传递参数给线程函数,并在处理线程时进行更细粒度的控制。
05
std::thread 线程构造函数
以下是 std::thread 构造函数的几种常用形式:
默认构造函数:创建一个未关联任何线程的 std::thread 对象。
std::thread t;
函数构造函数:接受一个可调用对象(如函数、lambda表达式或函数对象)作为参数,创建并启动一个新线程。
std::thread t(threadFunction);
参数化函数构造函数:接受一个可调用对象和若干参数,这些参数将被传递给可调用对象。
std::thread t(threadFunction, arg1, arg2, ...);
复制构造函数(已删除):std::thread 的复制构造函数被删除,因此不能通过复制来复制线程对象。
移动构造函数:接受一个 std::thread 对象作为参数,转移线程所有权。
std::thread t1(threadFunction);
std::thread t2 = std::move(t1);
从 std::thread::id 构造:接受一个 std::thread::id 类型的参数,但通常不直接使用。
std::thread::id id;
std::thread t(id);
接受现有线程的构造函数:接受一个已经存在的 std::thread 对象,创建一个新的线程对象,两者将共享同一个线程。
std::thread t1(threadFunction);
std::thread t2 = t1; // t2 现在引用 t1 的线程
06
std::thread 线程状态属性
在C++中,std::thread 类并没有直接提供线程状态属性,如线程是否正在运行、阻塞或已完成。然而,你可以使用一些方法来推断线程的状态或与之相关的信息:
joinable():
joinable成员函数可以用来检查线程是否可加入,即线程是否已经启动且尚未完成。如果线程已经启动且未完成,返回 true;如果线程尚未启动或已经完成,返回 false。
std::thread t(threadFunction);
bool isThreadRunning = t.joinable(); // 检查线程是否可加入
get_id():
get_id成员函数返回线程的唯一标识符。如果线程未启动或已经结束,返回 std::thread::id()。
std::thread::id id = t.get_id(); // 获取线程ID
join():
调用 join() 会等待线程完成。如果线程已经完成,join() 将立即返回。
t.join(); // 等待线程t完成
detach():
调用 detach() 会分离线程,使其在后台运行。分离后的线程将无法被 join() 或 cancel()。
t.detach(); // 线程在后台继续运行
硬件线程数:
std::thread::hardware_concurrency() 函数可以用来获取系统支持的硬件线程数,这有助于确定并行任务的最佳数量。
std::thread::hardware_concurrency(); // 获取硬件线程数
自定义同步机制:
使用 std::mutex、std::condition_variable 或 std::atomic 等同步机制,可以自定义线程状态的检查和控制。
07
小结
#include
#include
using namespace std;
void foo(int Z) { // 一个虚拟函数
for (int i = 0; i < Z; i++) {
cout << "线程使用函数指针作为可调用参数\n";
}
}
class thread_obj { // 可调用对象
public:
void operator()(int x) {
for (int i = 0; i < x; i++)
cout << "线程使用函数对象作为可调用参数\n";
}
};
int main() {
thread th1(foo, 3); // 函数指针
thread th2(thread_obj(), 3); // 函数对象
auto f = [](int x) { // 定义 Lambda 表达式
for (int i = 0; i < x; i++)
cout << "线程使用 lambda 表达式作为可调用参数\n";
};
thread th3(f, 3); // 线程通过使用 lambda 表达式作为可调用的参数
th1.join(); // 等待线程 t1 t2 t3完成
th2.join();
th3.join();
return 0;
}