1. 先看下比较权威的解释
2. 白话文聊聊
2.1 std::thread
std::thread是一个c++标准库类,它允许你在c++程序中创建和管理线程。它为处理线程提供了一个高级、可移植的接口,是C++ 11及以后标准的一部分。
#include <iostream>
#include <thread>
// Function that will be executed in the new thread
void threadDemo() {
std::cout << "Hello from the new thread!" << std::endl;
}
int main() {
// Create a new thread and pass the function to execute
std::thread myThread(threadDemo);
// Do some work in the main thread
std::cout << "Hello from the main thread!" << std::endl;
// Wait for the new thread to finish
myThread.join();
return 0;
}
C++ 11及之后标准,可以将std::thread与lambda函数一起使用,创建并启动一个线程来执行lambda中定义的代码。这是一种启动线程的便捷方式,无需定义单独的函数。同时std::thread构造函数中的lambda函数可以从周围的作用域中捕获和使用变量,这使得它成为向新线程传递数据和任务的一种灵活方式。
#include <iostream>
#include <thread>
int main() {
int value = 42;
std::thread myThread([value]() {
std::cout << "Value from the lambda: " << value << std::endl;
});
// ...
myThread.join();
return 0;
}
上面两个例子是不是很简单.....
2.1.1 std::thread如何调用类的成员函数
要在c++中使用std::thread调用类成员函数,需要向std::thread提供以下信息:
- 指向调用成员函数的对象的指针或引用。
- 成员函数本身;
#include <iostream>
#include <thread>
class MyClass {
public:
void memberFunction(int x, const std::string& str) {
std::cout << "Member function started. x = " << x << ", str = " << str << std::endl;
// Perform some work in the member function
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Member function completed." << std::endl;
}
};
int main() {
MyClass myObject; // Create an instance of the class
// Create a new thread and call the member function
std::thread myThread(&MyClass::memberFunction, &myObject, 58, "Hello from thread!");
// Do some work in the main thread
std::cout << "Hello from the main thread!" << std::endl;
// Wait for the new thread to finish
myThread.join();
return 0;
}
上述代码中,我们创建了一个MyClass的实例myObject,创建了一个新线程myThread,并指定要调用的成员函数(&MyClass::memberFunction)。
我们还传递了一个指向myObject的指针,作为调用成员函数的对象。
2.2 std::bind
std::bind是一个c++标准库函数模板,通过将参数绑定到可调用实体(函数或成员函数),用于创建可调用对象(函数对象)。它允许用较少的参数,或对参数重新排序来创建函数。
当需要将带有特定参数的函数传递给算法、回调函数或其他需要特定参数的函数时,std::bind特别有用。
std::bind的语法如下所示:
#include <functional>
std::bind(Function, arg1, arg2, ...);
- Function:要绑定参数的可调用实体(函数或成员函数)。
- arg1, arg2,…:绑定到可调用实体的参数。它们可以是值或占位符。
下面是std::bind的一些常见用例:
2.2.1 将参数绑定到函数:
#include <iostream>
#include <functional>
int add(int a, int b) {
return a + b;
}
int main() {
auto add5 = std::bind(add, 5, std::placeholders::_1);
std::cout << add5(10) << std::endl; // Calls add(5, 10)
return 0;
}
在这个例子中,我们使用std::bind创建了一个新的函数对象add5,它将add函数的第一个参数绑定到了值5上。当我们调用add5(10)时,它实际上调用了add(5, 10)。
2.2.2 绑定类的成员函数
#include <iostream>
#include <functional>
class MyClass {
public:
void printMessage(const std::string& message) {
std::cout << "Message: " << message << std::endl;
}
};
int main() {
MyClass obj;
auto printFunc = std::bind(&MyClass::printMessage, &obj, std::placeholders::_1);
printFunc("Hello, world!");
return 0;
}
在这个例子中,使用std::bind创建了一个可调用对象printFunc,它将MyClass的printMessage成员函数绑定到obj实例上。
在这个例子中,std::placeholders::_1被用作为printMessage成员函数的第一个参数。
在c++中使用std::thread/std::bind时,&符号用于获取函数或成员函数的地址。这是必要的,因为std::bind需要一个可调用对象、函数指针或函数引用作为它的第一个参数。由于成员函数不是独立函数,不能像自由函数那样直接作为函数指针传递,因此需要显式地获取它们的地址。
如果不使用&来获取成员函数的地址,编译器将抛出错误,因为它无法解释仅使用成员函数的名称而不使用上下文意味着什么。
同样的逻辑也适用于静态成员函数和非成员函数。
2.2.3 重新排序参数
#include <iostream>
#include <functional>
int subtract(int a, int b) {
return a - b;
}
int main() {
auto subtractReordered = std::bind(subtract, std::placeholders::_2, std::placeholders::_1);
std::cout << subtractReordered(10, 5) << std::endl; // Calls subtract(5, 10)
return 0;
}
在这个例子中,我们使用std::bind创建了一个新的函数对象subtractReordered,它在调用subtract函数时交换了参数的顺序。
无论绑定的是类成员函数还是非成员函数,std::bind都允许自定义参数,重新排序,并使用特定的参数绑定创建可调用对象。