Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 60 additions & 4 deletions mingw.shared_mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,39 +259,95 @@ class shared_timed_mutex : shared_mutex
using Base::unlock_shared;

template< class Clock, class Duration >
bool try_lock_until ( const std::chrono::time_point<Clock,Duration>& cutoff )
bool try_lock_until ( const std::chrono::time_point<Clock, Duration>& cutoff )
{
#if __cplusplus > 201703L
static_assert(chrono::is_clock_v<Clock>);
#endif
// The user-supplied clock may not tick at the same rate as
// steady_clock, so we must loop in order to guarantee that
// the timeout has expired before returning false.
#if __cplusplus >= 201402L
typename Clock::time_point __now = Clock::now();
#endif
do
{
#if __cplusplus >= 201402L
auto rel_time = cutoff - __now;
if (try_lock(rel_time))
#else
if (try_lock())
#endif
return true;
#if __cplusplus >= 201402L
__now = Clock::now();
#endif
}
#if __cplusplus >= 201402L
while (cutoff > __now);
#else
while (std::chrono::steady_clock::now() < cutoff);
#endif
return false;
}

template< class Rep, class Period >
bool try_lock_for (const std::chrono::duration<Rep,Period>& rel_time)
bool try_lock_for (const std::chrono::duration<Rep, Period>& rel_time)
{
#if __cplusplus >= 201402L
auto __rt = chrono::duration_cast<std::chrono::steady_clock::duration>(rel_time);
if (ratio_greater<std::chrono::steady_clock::period, Period>())
++__rt;
return try_lock_until(std::chrono::steady_clock::now() + __rt);
#else
return try_lock_until(std::chrono::steady_clock::now() + rel_time);
#endif
}

template< class Clock, class Duration >
bool try_lock_shared_until ( const std::chrono::time_point<Clock,Duration>& cutoff )
bool try_lock_shared_until ( const std::chrono::time_point<Clock, Duration>& cutoff )
{
#if __cplusplus > 201703L
static_assert(chrono::is_clock_v<Clock>);
#endif
// The user-supplied clock may not tick at the same rate as
// steady_clock, so we must loop in order to guarantee that
// the timeout has expired before returning false.
#if __cplusplus >= 201402L
typename Clock::time_point __now = Clock::now();
#endif
do
{
#if __cplusplus >= 201402L
auto rel_time = cutoff - __now;
if (try_lock_shared(rel_time))
#else
if (try_lock_shared())
#endif
return true;
#if __cplusplus >= 201402L
__now = Clock::now();
#endif
}
#if __cplusplus >= 201402L
while (cutoff > __now);
#else
while (std::chrono::steady_clock::now() < cutoff);
#endif
return false;
}

template< class Rep, class Period >
bool try_lock_shared_for (const std::chrono::duration<Rep,Period>& rel_time)
bool try_lock_shared_for (const std::chrono::duration<Rep, Period>& rel_time)
{
#if __cplusplus >= 201402L
auto __rt = chrono::duration_cast<std::chrono::steady_clock::duration>(rel_time);
if (ratio_greater<std::chrono::steady_clock::period, Period>())
++__rt;
return try_lock_shared_until(std::chrono::steady_clock::now() + __rt);
#else
return try_lock_shared_until(std::chrono::steady_clock::now() + rel_time);
#endif
}
};

Expand Down
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