文章目录
- 一、std::ref`的作用
- [二、 使用指针和lambda表达式的好处<br><br>](#二、 使用指针和lambda表达式的好处
) - 三、模板可变参数与引用折叠
一、std::ref`的作用
在多线程编程中,std::ref
是一个非常有用的工具,它允许我们将引用传递给线程函数,而不是传递副本。这在某些情况下可以避免不必要的拷贝,提高效率。例如:
cpp
void Print1(size_t n, const std::string& s, std::mutex& m, int& rx);
如果直接这样传递参数会报错:
同时在线程函数中对a修改,不会影响外部实参,因为:线程函数参数虽然是引用方式,但其实际引用的是线程栈中的拷贝
cpp
// unknown-type std::invoke(_Callable &&,_Ty1 &&,_Types2 &&...) noexcept(<expr>)
std::thread t1(Print1, 100, "hello mutex", std::ref(mtx), std::ref(x));
这里std::ref
将mtx
和x
的引用传递给了线程函数Print1
,而不是它们的副本。如果不使用std::ref
,mtx
和x
将会被拷贝,这可能导致线程间无法正确共享资源。
二、 使用指针和lambda表达式的好处
在多线程编程中,线程函数的参数传递是一个关键问题。使用指针和lambda表达式可以有效避免引用带来的麻烦。例如,lambda表达式可以捕获上下文变量,并以值或引用的方式传递给线程函数,简化代码并避免引用悬挂或生命周期问题。
cpp
void Print(size_t n, size_t j, const std::string& s) {
for (size_t i = j; i < j + n; i++) {
std::cout << std::this_thread::get_id() << " " << s << ": " << i << std::endl;
}
}
int main() {
std::thread t1(Print, 100, 1, "Thread 1");
std::thread t2([=]() {
Print(100, 101, "Thread 2");
});
t1.join();
t2.join();
return 0;
}
三、模板可变参数与引用折叠
(一)模板可变参数
模板可变参数是C++11引入的一个强大特性,它允许函数接受任意数量和类型的参数。std::thread
的构造函数利用了模板可变参数,能够接受任意类型的参数,并将它们转发给线程函数。例如:
cpp
template <class F, class... Args>
explicit std::thread(F&& f, Args&&... args);
这里的Args&&... args
表示可变参数模板,std::thread
会将这些参数转发给线程函数。
(二)引用折叠
引用折叠是C++11中引入的一个机制,用于处理引用的传递和绑定。它的主要规则如下:
• 左值引用折叠:如果一个引用被绑定到一个左值,那么它会被折叠为左值引用。
• 右值引用折叠:如果一个引用被绑定到一个右值,那么它会被折叠为右值引用。
• 混合引用折叠:如果一个引用被绑定到一个左值或右值,那么它会被折叠为左值引用。
引用折叠的作用是确保参数的正确传递,避免不必要的拷贝和悬挂引用问题。例如:
注意:如果是类成员函数作为线程参数时,必须将this作为线程函数参数。