如何检索指向在单独线程上运行的函数的移动指针?
How to retrieve a moved pointer to a function that runs on a separate thread?
当函数在单独的线程上运行时,如何检索已移入该函数的 std::unique_ptr
指针?
考虑以下示例:
using IntPtr = std::unique_ptr<int>;
IntPtr&& update(IntPtr &&fp_)
{
*fp_ = 23;
return std::move(fp_);
}
int main()
{
IntPtr foo_ptr = std::make_unique<int>(0);
foo_ptr = update(std::move(foo_ptr));
std::cout<< "data: " << *foo_ptr <<std::endl;
}
这很好。 foo_ptr
移入 update()
上的 fp_
,然后检索(移回)到 foo_ptr
。
如果 update()
是 运行 在单独的线程上,我如何检索 foo_ptr
???
using IntPtr = std::unique_ptr<int>;
IntPtr&& update(IntPtr &&fp_)
{
*fp_ = 23;
return std::move(fp_);
}
int main()
{
IntPtr foo_ptr = std::make_unique<int>(0);
std::thread foo_thread(update,std::move(foo_ptr));
foo_thread.join();
std::cout<< "data: " << *foo_ptr <<std::endl; // SEGFAULT because foo_ptr is a nullptr.
}
你不知道。
您将内存的所有权交给了另一个线程。该线程现在拥有该内存并将在它终止时将其删除。 join
后不存在了,你也没有把指针移回主线程。
如果你想让一个线程为另一个线程填充一些数据,那么要么你需要使用共享所有权,要么生产线程根本不应该拥有内存(即:你传递一个原始指针)。
或者只使用 packaged_task<int(int)>
,你根本不需要(直接)分配内存:
int update(int value)
{
return 23;
}
int main()
{
int value = 0;
std::packaged_task<int(int)> task(update);
auto future_int = task.get_future();
std::thread foo_thread(std::move(task), value);
foo_thread.join();
std::cout<< "data: " << future_int.get() <<std::endl;
}
最简单的方法是使用一个包装函数将结果写回到 foo_ptr
:
std::thread foo_thread([&foo_ptr]() {
foo_ptr = update(std::move(foo_ptr));
});
foo_thread.join();
std::cout<< "data: " << *foo_ptr <<std::endl;
请注意,尽管在 std::thread
构造函数调用和 join()
调用完成之间,主线程不得以任何方式访问 foo_ptr
。这样做将是一场数据竞赛。在构造函数之前和 join
之后,这很好,因为这两个调用都用作同步点,但两者之间的任何访问都将是不同步的,并且会与 lambda 内部对 foo_ptr
的写入竞争。
如果这听起来太危险,请考虑一种方法,线程将结果放入 std::promise
,然后主线程从相应的 std::future
:
中检索对象
std::promise<IntPtr> p;
std::future<IntPtr> fut = p.get_future();
std::thread foo_thread([ptr = std::move(foo_ptr), p = std::move(p)]() mutable {
p.set_value(update(std::move(ptr)));
});
foo_ptr = std::move(fut.get());
当函数在单独的线程上运行时,如何检索已移入该函数的 std::unique_ptr
指针?
考虑以下示例:
using IntPtr = std::unique_ptr<int>;
IntPtr&& update(IntPtr &&fp_)
{
*fp_ = 23;
return std::move(fp_);
}
int main()
{
IntPtr foo_ptr = std::make_unique<int>(0);
foo_ptr = update(std::move(foo_ptr));
std::cout<< "data: " << *foo_ptr <<std::endl;
}
这很好。 foo_ptr
移入 update()
上的 fp_
,然后检索(移回)到 foo_ptr
。
如果 update()
是 运行 在单独的线程上,我如何检索 foo_ptr
???
using IntPtr = std::unique_ptr<int>;
IntPtr&& update(IntPtr &&fp_)
{
*fp_ = 23;
return std::move(fp_);
}
int main()
{
IntPtr foo_ptr = std::make_unique<int>(0);
std::thread foo_thread(update,std::move(foo_ptr));
foo_thread.join();
std::cout<< "data: " << *foo_ptr <<std::endl; // SEGFAULT because foo_ptr is a nullptr.
}
你不知道。
您将内存的所有权交给了另一个线程。该线程现在拥有该内存并将在它终止时将其删除。 join
后不存在了,你也没有把指针移回主线程。
如果你想让一个线程为另一个线程填充一些数据,那么要么你需要使用共享所有权,要么生产线程根本不应该拥有内存(即:你传递一个原始指针)。
或者只使用 packaged_task<int(int)>
,你根本不需要(直接)分配内存:
int update(int value)
{
return 23;
}
int main()
{
int value = 0;
std::packaged_task<int(int)> task(update);
auto future_int = task.get_future();
std::thread foo_thread(std::move(task), value);
foo_thread.join();
std::cout<< "data: " << future_int.get() <<std::endl;
}
最简单的方法是使用一个包装函数将结果写回到 foo_ptr
:
std::thread foo_thread([&foo_ptr]() {
foo_ptr = update(std::move(foo_ptr));
});
foo_thread.join();
std::cout<< "data: " << *foo_ptr <<std::endl;
请注意,尽管在 std::thread
构造函数调用和 join()
调用完成之间,主线程不得以任何方式访问 foo_ptr
。这样做将是一场数据竞赛。在构造函数之前和 join
之后,这很好,因为这两个调用都用作同步点,但两者之间的任何访问都将是不同步的,并且会与 lambda 内部对 foo_ptr
的写入竞争。
如果这听起来太危险,请考虑一种方法,线程将结果放入 std::promise
,然后主线程从相应的 std::future
:
std::promise<IntPtr> p;
std::future<IntPtr> fut = p.get_future();
std::thread foo_thread([ptr = std::move(foo_ptr), p = std::move(p)]() mutable {
p.set_value(update(std::move(ptr)));
});
foo_ptr = std::move(fut.get());