源于通义千问
在 C++ 中,std::thread
支持传递多种类型的函数作为线程入口点。你可以传递普通函数、类的成员函数、Lambda 表达式、函数对象(仿函数)等。以下是详细的说明和示例。
1. 传递普通函数
普通函数是最简单的用法。
示例
cpp
#include <iostream>
#include <thread>
void myFunction(int x) {
std::cout << "Thread ID: " << std::this_thread::get_id()
<< ", Value: " << x << std::endl;
}
int main() {
// 创建线程并传递普通函数
std::thread t(myFunction, 42);
// 等待线程完成
if (t.joinable()) {
t.join();
}
return 0;
}
输出
Thread ID: 140735212345678, Value: 42
2. 传递类的成员函数
传递类的成员函数时,需要提供类实例的指针或引用。
示例
cpp
#include <iostream>
#include <thread>
class MyClass {
public:
void memberFunction(int x) {
std::cout << "Thread ID: " << std::this_thread::get_id()
<< ", Value: " << x << std::endl;
}
};
int main() {
MyClass obj;
// 创建线程并传递成员函数
std::thread t(&MyClass::memberFunction, &obj, 42);
// 等待线程完成
if (t.joinable()) {
t.join();
}
return 0;
}
输出
Thread ID: 140735212345678, Value: 42
3. 传递 Lambda 表达式
Lambda 表达式是一种简洁的方式,尤其适合定义临时逻辑。
示例
cpp
#include <iostream>
#include <thread>
int main() {
int value = 42;
// 使用 Lambda 表达式创建线程
std::thread t([value]() {
std::cout << "Thread ID: " << std::this_thread::get_id()
<< ", Value: " << value << std::endl;
});
// 等待线程完成
if (t.joinable()) {
t.join();
}
return 0;
}
输出
Thread ID: 140735212345678, Value: 42
4. 传递函数对象(仿函数)
函数对象是重载了 operator()
的类实例,可以像函数一样调用。
示例
cpp
#include <iostream>
#include <thread>
class Functor {
public:
void operator()(int x) const {
std::cout << "Thread ID: " << std::this_thread::get_id()
<< ", Value: " << x << std::endl;
}
};
int main() {
Functor f;
// 创建线程并传递函数对象
std::thread t(f, 42);
// 等待线程完成
if (t.joinable()) {
t.join();
}
return 0;
}
输出
Thread ID: 140735212345678, Value: 42
5. 传递绑定器(std::bind
)
使用 std::bind
可以将函数及其参数绑定在一起,生成一个可调用对象。
示例
cpp
#include <iostream>
#include <thread>
#include <functional>
void myFunction(int x) {
std::cout << "Thread ID: " << std::this_thread::get_id()
<< ", Value: " << x << std::endl;
}
int main() {
// 使用 std::bind 绑定函数和参数
auto boundFunction = std::bind(myFunction, 42);
// 创建线程并传递绑定器
std::thread t(boundFunction);
// 等待线程完成
if (t.joinable()) {
t.join();
}
return 0;
}
输出
Thread ID: 140735212345678, Value: 42
6. 传递可调用对象(如 std::function
)
std::function
是一个通用的函数包装器,可以存储任何可调用对象。
示例
cpp
#include <iostream>
#include <thread>
#include <functional>
void myFunction(int x) {
std::cout << "Thread ID: " << std::this_thread::get_id()
<< ", Value: " << x << std::endl;
}
int main() {
// 使用 std::function 存储可调用对象
std::function<void()> callable = std::bind(myFunction, 42);
// 创建线程并传递 std::function
std::thread t(callable);
// 等待线程完成
if (t.joinable()) {
t.join();
}
return 0;
}
输出
Thread ID: 140735212345678, Value: 42
总结
- 普通函数:直接传递函数名。
- 类的成员函数:需要提供类实例的指针或引用。
- Lambda 表达式:适合定义临时逻辑。
- 函数对象 :重载
operator()
的类实例。 - 绑定器(
std::bind
):用于绑定函数和参数。 std::function
:通用的函数包装器。
多个线程、多个参数
在 C++ 中,如果需要通过 std::thread
传递多个参数给类的成员函数,可以直接将这些参数依次传递给线程构造函数。std::thread
会自动将这些参数转发给目标函数。
以下是详细的示例,展示如何传递多个参数给类的成员函数,并将其存储在 std::vector<std::thread>
中。
示例代码
cpp
#include <iostream>
#include <thread>
#include <vector>
class MyClass {
public:
// 成员函数,接受多个参数
void memberFunction(int threadId, const std::string& message, double value) {
std::cout << "Thread ID: " << std::this_thread::get_id()
<< ", Thread Number: " << threadId
<< ", Message: " << message
<< ", Value: " << value << std::endl;
}
};
int main() {
const int numThreads = 5; // 线程数量
MyClass myClassInstance; // 类实例
std::vector<std::thread> threads; // 存储线程的容器
// 创建多个线程并传递多个参数给类的成员函数
for (int i = 0; i < numThreads; ++i) {
threads.emplace_back(&MyClass::memberFunction, &myClassInstance,
i, "Hello from thread", 3.14 + i);
}
// 等待所有线程完成
for (auto& t : threads) {
if (t.joinable()) {
t.join();
}
}
std::cout << "All threads finished." << std::endl;
return 0;
}
代码解析
-
类定义
- 定义了一个类
MyClass
,其中包含一个成员函数memberFunction
,该函数接受三个参数:int threadId
:线程编号。const std::string& message
:字符串消息。double value
:浮点数值。
- 定义了一个类
-
创建类实例
- 在
main
函数中,创建了MyClass
的实例myClassInstance
。
- 在
-
创建线程
-
使用
std::vector<std::thread>
存储多个线程。 -
使用
emplace_back
方法直接构造线程对象,并传递多个参数:cppthreads.emplace_back(&MyClass::memberFunction, &myClassInstance, i, "Hello from thread", 3.14 + i);
- 第一个参数是成员函数的指针:
&MyClass::memberFunction
。 - 第二个参数是类实例的地址:
&myClassInstance
。 - 后续参数是传递给成员函数的多个参数:
i
(当前线程编号)、"Hello from thread"
(字符串)和3.14 + i
(浮点数)。
- 第一个参数是成员函数的指针:
-
-
等待线程完成
- 遍历
threads
容器,调用每个线程的join()
方法,确保主线程等待所有子线程完成。
- 遍历
输出示例
运行程序后,输出可能如下(线程 ID 可能不同):
Thread ID: 140735212345678, Thread Number: 0, Message: Hello from thread, Value: 3.14
Thread ID: 140735212345789, Thread Number: 1, Message: Hello from thread, Value: 4.14
Thread ID: 140735212345890, Thread Number: 2, Message: Hello from thread, Value: 5.14
Thread ID: 140735212345991, Thread Number: 3, Message: Hello from thread, Value: 6.14
Thread ID: 140735212346092, Thread Number: 4, Message: Hello from thread, Value: 7.14
All threads finished.
注意事项
-
参数类型匹配
- 确保传递给线程的参数类型与目标函数的参数类型匹配。例如,如果函数参数是引用类型(如
const std::string&
),则可以传递临时对象或变量。
- 确保传递给线程的参数类型与目标函数的参数类型匹配。例如,如果函数参数是引用类型(如
-
参数拷贝与移动
- 如果传递的是复杂对象(如自定义类或容器),注意对象的拷贝或移动行为。可以通过
std::ref
或std::move
显式控制。
- 如果传递的是复杂对象(如自定义类或容器),注意对象的拷贝或移动行为。可以通过
-
线程安全
- 如果多个线程访问共享资源(如类的成员变量),需要使用互斥锁(
std::mutex
)或其他同步机制来确保线程安全。
- 如果多个线程访问共享资源(如类的成员变量),需要使用互斥锁(
-
C++11 及以上版本
- 上述代码需要 C++11 或更高版本支持。确保编译器支持 C++11,并使用适当的编译选项(例如
-std=c++11
)。
- 上述代码需要 C++11 或更高版本支持。确保编译器支持 C++11,并使用适当的编译选项(例如