Skip to content

Commit

Permalink
Fix fatal bug: Threads must copy arguments. (#59)
Browse files Browse the repository at this point in the history
Threads were taking arguments by reference, rather than creating copies. This has been altered to the correct behavior, which should fix several fatal (and subtle) errors.
Adds a regression test that will automatically detect similar failures (with high probability).

Recommend immediate update and recompilation of all projects using this library.
  • Loading branch information
nmcclatchey authored and alxvasilev committed Sep 15, 2019
1 parent 55a5e49 commit 86ca7dc
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 4 deletions.
12 changes: 8 additions & 4 deletions mingw.thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,22 @@ namespace detail
template<class Func, typename... Args>
class ThreadFuncCall
{
typedef std::tuple<Args...> Tuple;
Func mFunc;
using Tuple = std::tuple<typename std::decay<Args>::type...>;
typename std::decay<Func>::type mFunc;
Tuple mArgs;

template <std::size_t... S>
void callFunc(detail::IntSeq<S...>)
{
detail::invoke(std::forward<Func>(mFunc), std::get<S>(std::forward<Tuple>(mArgs)) ...);
// Note: Only called once (per thread)
detail::invoke(std::move(mFunc), std::move(std::get<S>(mArgs)) ...);
}
public:
ThreadFuncCall(Func&& aFunc, Args&&... aArgs)
:mFunc(std::forward<Func>(aFunc)), mArgs(std::forward<Args>(aArgs)...){}
: mFunc(std::forward<Func>(aFunc)),
mArgs(std::forward<Args>(aArgs)...)
{
}

void callFunc()
{
Expand Down
27 changes: 27 additions & 0 deletions tests/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,33 @@ int main()
std::hash<thread::id> hasher;
std::cout << "Hash:\t" << hasher(this_thread::get_id()) << "\n";
}

// Regression test: Thread must copy any argument that is passed by value.
{
std::vector<std::thread> loop_threads;
std::atomic<int> i_vals_touched [4];// { 0, 0, 0, 0 };
for (int i = 0; i < 4; ++i)
i_vals_touched[i].store(0, std::memory_order_relaxed);
for (int i = 0; i < 4; ++i)
{
loop_threads.push_back(std::thread([&](int c)
{
log("For-loop test thread got value: %i", c);
i_vals_touched[c].fetch_add(1, std::memory_order_relaxed);
}, i));
}
for (std::thread & thr : loop_threads)
thr.join();
for (int i = 0; i < 4; ++i)
{
if (i_vals_touched[i] != 1)
{
log("FATAL: Threads are not copying arguments!");
return 1;
}
}
}

std::thread t([](TestMove&& a, const char* b, int c) mutable
{
try
Expand Down

0 comments on commit 86ca7dc

Please sign in to comment.