Fix Win32Thread not capturing by move

std::function does not allow non-movable lambdas, so capturing by move
doesn't work there. And the old solution of course has issues with
dangling pointers (but because this is C++ the compiler still thinks
it's A-Ok).
This commit is contained in:
Robbert van der Helm
2020-10-27 22:53:59 +01:00
parent 1a18ea8614
commit eb8d4ae1d8
2 changed files with 24 additions and 29 deletions
+2 -1
View File
@@ -18,7 +18,8 @@
PluginContext::PluginContext() : context(), events_timer(context) {}
uint32_t WINAPI win32_thread_trampoline(std::function<void()>* entry_point) {
uint32_t WINAPI
win32_thread_trampoline(fu2::unique_function<void()>* entry_point) {
(*entry_point)();
delete entry_point;
+22 -28
View File
@@ -29,6 +29,7 @@
#include <windows.h>
#include <boost/asio/io_context.hpp>
#include <function2/function2.hpp>
/**
* The delay between calls to the event loop at an even more than cinematic 30
@@ -122,19 +123,11 @@ class PluginContext {
* We can't store the function pointer in the `Win32Thread` object because
* moving a `Win32Thread` object would then cause issues.
*
* @param win32_thread_trampoline A `std::function<void()>*` pointer to a
* function pointer, great.
* @param entry_point A `fu2::unique_function<void()>*` pointer to a function
* pointer, great.
*/
uint32_t WINAPI win32_thread_trampoline(std::function<void()>* entry_point);
/**
* Taken from the C++ reference:
* https://en.cppreference.com/w/cpp/thread/jthread
*/
template <class T>
std::decay_t<T> decay_copy(T&& v) {
return std::forward<T>(v);
}
uint32_t WINAPI
win32_thread_trampoline(fu2::unique_function<void()>* entry_point);
/**
* A simple RAII wrapper around the Win32 thread API that imitates
@@ -166,24 +159,25 @@ class Win32Thread {
* @param entry_point The thread entry point that should be run.
* @param parameter The parameter passed to the entry point function.
*/
template <class Function, class... Args>
template <typename Function, typename... Args>
Win32Thread(Function&& f, Args&&... args)
: handle(
CreateThread(nullptr,
0,
reinterpret_cast<LPTHREAD_START_ROUTINE>(
win32_thread_trampoline),
// We'll capture the function by move since the
// lambda will often go out of scope in the time that
// the thread is starting. Alternatively we could
// wait for the thread to be up before continuing,
// that may be a bit safer.
new std::function<void()>([&, f = std::move(f)]() {
std::invoke(
f, decay_copy(std::forward<Args>(args))...);
}),
0,
nullptr),
CreateThread(
nullptr,
0,
reinterpret_cast<LPTHREAD_START_ROUTINE>(
win32_thread_trampoline),
// `std::function` does not support functions with move
// captures the function has to be copy-constructable.
// Function2's unique_function lets us capture and move our
// arguments to the lambda so we don't end up with dangling
// references.
new fu2::unique_function<void()>(
[f = std::move(f), ... args = std::move(args)]() mutable {
f(std::move(args)...);
}),
0,
nullptr),
CloseHandle) {}
Win32Thread(const Win32Thread&) = delete;