C++11——多线程编程3
翻译来自:https://thispointer.com//c11-multithreading-part-3-carefully-pass-arguments-to-threads/
要将参数传递给线程的可关联对象或函数,只需将参数传递给std::thread构造函数。
默认情况下,所有的参数都将复制到新线程的内部存储中。
#include <iostream> #include <string> #include <thread> void threadCallback(int x, std::string str) { std::cout << "Passed Number = " << x << std::endl; std::cout << "Passed String = " << str << std::endl; } int main() { int x = 10; std::string str = "Sample String"; std::thread threadObj(threadCallback, x, str); threadObj.join(); return 0; }
不要将变量的地址从本地堆栈传递给线程的回调函数。因为线程 1 中的局部变量可能已经销毁,但线程 2 仍在尝试通过其地址访问它。
在这种情况下,访问无效地址可能会导致意外行为
#include <iostream> #include <thread> void newThreadCallback(int* p) { std::cout << "Inside Thread : "" : p = " << p << std::endl; std::chrono::milliseconds dura(1000); std::this_thread::sleep_for(dura); *p = 19; } void startNewThread() { int i = 10; std::cout << "Inside Main Thread : "" : i = " << i << std::endl; std::thread t(newThreadCallback, &i); t.detach(); std::cout << "Inside Main Thread : "" : i = " << i << std::endl; } int main() { startNewThread(); std::chrono::milliseconds dura(2000); std::this_thread::sleep_for(dura); return 0; }
同样的,在传递指向堆内存的指针给heap时,因为某些线程可能在新线程尝试访问它之前删除该内存。
在这种情况下,访问无效地址可能会导致不可预测的行为。
#include <iostream> #include <thread> void newThreadCallback(int* p) { std::cout << "Inside Thread : "" : p = " << p << std::endl; std::chrono::milliseconds dura(1000); std::this_thread::sleep_for(dura); *p = 19; std::cout << *p << std::endl; } void startNewThread() { int* p = new int(); *p = 10; std::cout << "Inside Main Thread : "" : *p = " << *p << std::endl; std::thread t(newThreadCallback, p); t.detach(); delete p; p = NULL; } int main() { startNewThread(); std::chrono::milliseconds dura(2000); std::this_thread::sleep_for(dura); return 0; }
给线程传递引用
由于参数被复制到新的线程堆栈,所以,如果想通过常用的方式传递引用,如:
#include <iostream> #include <thread> void threadCallback(int const& x) { int& y = const_cast<int&>(x); y++; std::cout << "Inside Thread x = " << x << std::endl; } int main() { int x = 9; std::cout << "In Main Thread : Before Thread Start x = " << x << std::endl; std::thread threadObj(threadCallback, x); threadObj.join(); std::cout << "In Main Thread : After Thread Joins x = " << x << std::endl; return 0; }
即使threadCallback接受参数作为引用,但是并没有改变main中x的值,在线程引用外它是不可见的。
这是因为线程函数threadCallback中的x是引用复制在新线程的堆栈中的临时值。
如何修改:
使用 std::ref
#include <iostream> #include <thread> void threadCallback(int const& x) { int& y = const_cast<int&>(x); y++; std::cout << "Inside Thread x = " << x << std::endl; } int main() { int x = 9; std::cout << "In Main Thread : Before Thread Start x = " << x << std::endl; std::thread threadObj(threadCallback, std::ref(x)); threadObj.join(); std::cout << "In Main Thread : After Thread Joins x = " << x << std::endl; return 0; }
指定一个类的成员函数的指针作为线程函数
将指针传递给成员函数作为回调函数,并将指针指向对象作为第二个参数
#include <iostream> #include <thread> class DummyClass { public: DummyClass() {} DummyClass(const DummyClass& obj) {} void sampleMemberFunction(int x) { std::cout << "Inside sampleMemberFunction " << x << std::endl; } }; int main() { DummyClass dummyObj; int x = 10; std::thread threadObj(&DummyClass::sampleMemberFunction, &dummyObj, x); threadObj.join(); return 0; }