thread: remove thread, mutex, and condition_variable wrappers

These are no longer needed as we required MinGW with PThreads support.
This commit is contained in:
Danny Robson 2020-08-03 11:20:06 +10:00
parent e4eb234889
commit e8f23a349e
33 changed files with 101 additions and 663 deletions

View File

@ -104,7 +104,6 @@ list (
##-----------------------------------------------------------------------------
if (LINUX)
list (APPEND UTIL_FILES
thread/thread_std.hpp
thread/event_futex.cpp
thread/flag_futex.cpp
rand/system_linux.cpp
@ -174,41 +173,30 @@ endif ()
###############################################################################
list (APPEND UTIL_FILES
thread/condition_variable.hpp
thread/event.hpp
thread/flag.hpp
thread/mutex.hpp
thread/primitive.hpp
thread/semaphore.hpp
thread/thread.hpp
)
if (LINUX)
list (APPEND UTIL_FILES
thread/condition_variable_std.hpp
thread/event_futex.cpp
thread/event_futex.hpp
thread/semaphore_linux.hpp
thread/semaphore_linux.cpp
thread/flag_futex.cpp
thread/flag_futex.hpp
thread/mutex_std.hpp
)
elseif (WIN32)
list (APPEND UTIL_FILES
thread/condition_variable_win32.cpp
thread/condition_variable_win32.hpp
thread/event_std.cpp
thread/event_std.hpp
thread/event_win32.cpp
thread/mutex_win32.cpp
thread/mutex_win32.hpp
thread/semaphore_win32.hpp
thread/semaphore_win32.cpp
thread/flag_std.cpp
thread/flag_std.hpp
thread/thread_win32.cpp
thread/thread_win32.hpp
)
else ()
message (FATAL_ERROR "Unsupported thread platform")
@ -537,7 +525,6 @@ list (
thread/flag.hpp
thread/monitor.cpp
thread/monitor.hpp
thread/mutex.hpp
thread/ticketlock.cpp
thread/ticketlock.hpp
thread/spinlock.cpp
@ -740,15 +727,12 @@ if (TESTS)
stringid
stringcache
strongdef
thread/condition_variable
thread/event
thread/flag
thread/monitor
thread/mutex
thread/semaphore
thread/spinlock
thread/ticketlock
thread/thread
time/8601
traits
tuple/index

View File

@ -2,7 +2,9 @@
A simple cross-platform C++ utility library.
Supported compilers: >=clang-5.x, >=gcc7.x; specifically, we require cxx17 features such as structured bindings which aren't present in older compilers. No attempt has been made to compile under MSVC.
Supported compilers: >=clang-10.x, >=gcc10.x; specifically, we require cxx17 features such as structured bindings which aren't present in older compilers. No attempt has been made to compile under MSVC.
MinGW must be compiled with PThreads support so that the std threading API is available.
=== Environment Variables

View File

@ -27,7 +27,7 @@ queue::default_parallelism (void) noexcept
LOG_ERROR ("Unable to parse JOB_THREADS. Using the default");
}
return cruft::thread::thread::hardware_concurrency ();
return std::thread::hardware_concurrency ();
}
@ -62,7 +62,7 @@ queue::queue (unsigned thread_count, unsigned pool_size):
CHECK_GE (m_tasks.finishing.capacity (), thread_count);
for (auto &t: m_threads)
t = cruft::thread::thread (&queue::loop, this);
t = std::thread (&queue::loop, this);
}

View File

@ -14,7 +14,6 @@
#include "../thread/flag.hpp"
#include "../thread/monitor.hpp"
#include "../thread/semaphore.hpp"
#include "../thread/thread.hpp"
#include "../thread/ticketlock.hpp"
#include "../parallel/queue.hpp"
@ -25,6 +24,7 @@
#include <functional>
#include <new>
#include <vector>
#include <thread>
namespace cruft::job {
@ -201,10 +201,10 @@ namespace cruft::job {
thread::semaphore m_pending;
std::vector<thread::thread> m_threads;
std::vector<std::thread> m_threads;
thread::semaphore m_doomed;
thread::thread m_reaper;
std::thread m_reaper;
};
}

View File

@ -1,11 +1,10 @@
///////////////////////////////////////////////////////////////////////////////
#include "job/queue.hpp"
#include "thread/thread.hpp"
#include "tap.hpp"
#include <chrono>
#include <iostream>
#include <thread>
///////////////////////////////////////////////////////////////////////////////
@ -33,7 +32,7 @@ main (void)
std::atomic<int> count = 0;
{
cruft::job::queue q {cruft::thread::thread::hardware_concurrency (), INNER};
cruft::job::queue q {std::thread::hardware_concurrency (), INNER};
std::vector<cruft::job::queue::cookie> cookies;
std::generate_n (std::back_inserter (cookies), INNER, [&] () {
return q.submit (

View File

@ -1,12 +1,13 @@
#include "parallel/queue.hpp"
#include "thread/flag.hpp"
#include "thread/semaphore.hpp"
#include "thread/thread.hpp"
#include "tap.hpp"
#include <algorithm>
#include <thread>
static constexpr uint32_t slots = 4;
static constexpr int parallelism = 8;
@ -65,8 +66,8 @@ main ()
// start n consumers, and n producers that fill an array with integers
std::vector<int> dst (parallelism * chunk_size);
std::vector<cruft::thread::thread> consumers;
std::vector<cruft::thread::thread> producers;
std::vector<std::thread> consumers;
std::vector<std::thread> producers;
for (int i = 0; i < parallelism; ++i) {
consumers.emplace_back (

View File

@ -1,9 +1,9 @@
#include "thread/flag.hpp"
#include "thread/thread.hpp"
#include "parallel/stack.hpp"
#include "tap.hpp"
#include <thread>
int main ()
@ -57,8 +57,8 @@ int main ()
static int constexpr ITERATIONS = 8 * 1024;
cruft::parallel::stack<int> store (8);
cruft::thread::flag ev;
std::vector<cruft::thread::thread> contestants;
for (unsigned i = 0; i < cruft::thread::thread::hardware_concurrency () + 1; ++i)
std::vector<std::thread> contestants;
for (unsigned i = 0; i < std::thread::hardware_concurrency () + 1; ++i)
contestants.emplace_back (fight, std::ref (store), std::ref (ev), ITERATIONS);
ev.notify_all ();

View File

@ -1,4 +0,0 @@
int main ()
{
}

View File

@ -1,9 +1,9 @@
#include "thread/event.hpp"
#include "thread/thread.hpp"
#include "tap.hpp"
#include <atomic>
#include <thread>
int
@ -20,14 +20,14 @@ main ()
std::atomic<int> val = 0;
cruft::thread::event a;
cruft::thread::thread t ([&] () {
std::thread t ([&] () {
a.wait ();
++val;
});
// block for hopefully long enough to allow the above thread to change
// the value of the integer.
cruft::thread::this_thread::sleep_for (std::chrono::milliseconds (100));
std::this_thread::sleep_for (std::chrono::milliseconds (100));
tap.expect_eq (val, 0, "waiting actually blocks");

View File

@ -1,8 +1,9 @@
#include "thread/flag.hpp"
#include "thread/thread.hpp"
#include "tap.hpp"
#include <thread>
int
main ()
@ -12,12 +13,12 @@ main ()
cruft::thread::flag f;
std::atomic<int> value = 0;
cruft::thread::thread t1 ([&] () {
std::thread t1 ([&] () {
f.wait ();
value = 1;
});
cruft::thread::this_thread::sleep_for (std::chrono::milliseconds (100));
std::this_thread::sleep_for (std::chrono::milliseconds (100));
tap.expect_eq (value, 0, "value hasn't been set during wait");
f.notify_all ();
@ -25,12 +26,12 @@ main ()
t1.join ();
tap.expect_eq (value, 1, "value has been changed after wait");
cruft::thread::thread t2 ([&] () {
std::thread t2 ([&] () {
f.wait ();
value = 2;
});
cruft::thread::this_thread::sleep_for (std::chrono::milliseconds (100));
std::this_thread::sleep_for (std::chrono::milliseconds (100));
tap.expect_eq (value, 2, "second wait didn't appear to block");
t2.join ();
@ -59,13 +60,13 @@ main ()
}
};
std::vector<cruft::thread::thread> workers;
std::vector<std::thread> workers;
std::generate_n (
std::back_inserter (workers),
parallelism,
[&, i = 0] () mutable
{
return cruft::thread::thread { func, i++ };
return std::thread { func, i++ };
});
for (auto &t: workers)

View File

@ -9,11 +9,11 @@
#include "thread/event.hpp"
#include "thread/monitor.hpp"
#include "thread/semaphore.hpp"
#include "thread/thread.hpp"
#include "tap.hpp"
#include <atomic>
#include <thread>
///////////////////////////////////////////////////////////////////////////////
@ -49,8 +49,8 @@ main ()
auto &enter = obj->enter;
auto &leave = obj->leave;
cruft::thread::thread t1 ([&] () { obj->inc (); });
cruft::thread::thread t2 ([&] () { obj->inc (); });
std::thread t1 ([&] () { obj->inc (); });
std::thread t2 ([&] () { obj->inc (); });
tap.expect_eq (value, 0, "wrapped class was left initialised");

View File

@ -1,14 +0,0 @@
#include "tap.hpp"
#include "thread/mutex.hpp"
int main ()
{
cruft::TAP::logger tap;
cruft::thread::mutex a;
cruft::thread::mutex b;
(void)a;
(void)b;
return tap.status ();
}

View File

@ -1,10 +1,11 @@
#include "thread/semaphore.hpp"
#include "thread/flag.hpp"
#include "thread/thread.hpp"
#include "thread/mutex.hpp"
#include "tap.hpp"
#include <mutex>
#include <thread>
///////////////////////////////////////////////////////////////////////////////
void
@ -35,7 +36,7 @@ main ()
// the spawned thread attempts to double acquire a semaphore with
// only one available and so should get blocked immediately.
std::atomic<int> test = 0;
cruft::thread::thread t ([&] () {
std::thread t ([&] () {
sem.lock ();
sem.lock ();
test = 1;
@ -44,7 +45,7 @@ main ()
// wait until we know the thread should have been blocked. it should
// not have touched the 'test' variable at this point.
while (sem.value () > 0)
cruft::thread::this_thread::yield ();
std::this_thread::yield ();
tap.expect_eq (test, 0, "locking blocks in foreign thread");
@ -56,9 +57,9 @@ main ()
}
{
const auto parallelism = cruft::thread::thread::hardware_concurrency ();
const auto parallelism = std::thread::hardware_concurrency ();
constexpr int iterations = 1 << 16;
std::vector<cruft::thread::thread> threads;
std::vector<std::thread> threads;
cruft::thread::semaphore sem (0);

View File

@ -8,11 +8,11 @@
#include "thread/flag.hpp"
#include "thread/spinlock.hpp"
#include "thread/thread.hpp"
#include "tap.hpp"
#include <mutex>
#include <thread>
///////////////////////////////////////////////////////////////////////////////
@ -38,14 +38,14 @@ main ()
l.unlock ();
tap.expect (true, "unlocked without contention");
if (cruft::thread::thread::hardware_concurrency () < 2) {
if (std::thread::hardware_concurrency () < 2) {
tap.skip ("n-way fight");
} else {
constexpr int iterations = 1 << 12;
cruft::thread::flag start_flag;
std::vector<cruft::thread::thread> contestants;
for (unsigned i = 0; i < cruft::thread::thread::hardware_concurrency (); ++i)
std::vector<std::thread> contestants;
for (unsigned i = 0; i < std::thread::hardware_concurrency (); ++i)
contestants.emplace_back (fight, std::ref (start_flag), std::ref (l), iterations);
start_flag.notify_all ();
@ -53,7 +53,7 @@ main ()
for (auto &t: contestants)
t.join ();
tap.expect (true, "n-way fight, %! contestants", cruft::thread::thread::hardware_concurrency ());
tap.expect (true, "n-way fight, %! contestants", std::thread::hardware_concurrency ());
}
return tap.status ();

View File

@ -1,29 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2019 Danny Robson <danny@nerdcruft.net>
*/
#include "thread/thread.hpp"
#include "tap.hpp"
#include <atomic>
static void run (std::atomic<int> &val) { ++val; }
int main ()
{
cruft::TAP::logger tap;
// Get the thread to increment an int. If it's been incremented once after
// joining then we assume the thread ran successfully.
std::atomic<int> val = 0;
cruft::thread::thread dude (run, std::ref (val));
dude.join ();
tap.expect_eq (val.load (), 1, "thread appears to have run");
return tap.status ();
}

View File

@ -8,11 +8,12 @@
#include "thread/flag.hpp"
#include "thread/ticketlock.hpp"
#include "thread/thread.hpp"
#include "thread/mutex.hpp"
#include "tap.hpp"
#include <mutex>
#include <thread>
///////////////////////////////////////////////////////////////////////////////
using ffs_t = std::chrono::high_resolution_clock;
@ -44,7 +45,7 @@ main ()
l.unlock ();
tap.expect (true, "unlocked without contention");
if (true || cruft::thread::thread::hardware_concurrency () < 2) {
if (true || std::thread::hardware_concurrency () < 2) {
tap.skip ("reasonably fair under contention");
} else {
// measure fairness under contention is below some threshold
@ -63,7 +64,7 @@ main ()
ffs_t::time_point a_finish, b_finish;
cruft::thread::thread a (
std::thread a (
fight,
std::ref (start_flag),
std::ref (l),
@ -71,7 +72,7 @@ main ()
std::ref (a_finish)
);
cruft::thread::thread b (
std::thread b (
fight,
std::ref (start_flag),
std::ref (l),

View File

@ -1,19 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2019 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "../platform.hpp"
#if defined(PLATFORM_LINUX)
#include "condition_variable_std.hpp"
#elif defined(PLATFORM_WIN32)
#include "condition_variable_win32.hpp"
#else
#error "Unsupported platform for condition_variable"
#endif

View File

@ -1,17 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2019 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include <condition_variable>
namespace cruft::thread {
inline namespace std {
using condition_variable = ::std::condition_variable;
}
}

View File

@ -1,42 +0,0 @@
#include "condition_variable_win32.hpp"
#include <synchapi.h>
using cruft::thread::win32::condition_variable;
///////////////////////////////////////////////////////////////////////////////
condition_variable::condition_variable ()
: m_native (CONDITION_VARIABLE_INIT)
{
InitializeConditionVariable (&m_native);
}
//-----------------------------------------------------------------------------
condition_variable::~condition_variable ()
{ ; }
///////////////////////////////////////////////////////////////////////////////
void
condition_variable::wait (std::unique_lock<cruft::thread::mutex> &lock)
{
SleepConditionVariableCS (
&m_native, &lock.mutex ()->native_handle (), INFINITE
);
}
///////////////////////////////////////////////////////////////////////////////
void condition_variable::notify_one (void) noexcept
{
WakeConditionVariable (&m_native);
}
//-----------------------------------------------------------------------------
void condition_variable::notify_all () noexcept
{
WakeAllConditionVariable (&m_native);
}

View File

@ -1,61 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2019 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "mutex.hpp"
#include <mutex>
namespace cruft::thread {
inline namespace win32 {
enum class cv_status {
no_timeout,
timeout
};
class condition_variable {
public:
condition_variable ();
condition_variable (condition_variable const&) noexcept = delete;
condition_variable& operator= (condition_variable const&) = delete;
~condition_variable ();
void notify_one (void) noexcept;
void notify_all (void) noexcept;
void wait (std::unique_lock<mutex>&);
template <typename PredicateT>
void wait (
std::unique_lock<mutex> &lock,
PredicateT pred
) {
while (!pred ())
wait (lock);
}
template <class RepT, class PeriodT>
cv_status
wait_for (
std::unique_lock<mutex>& lock,
std::chrono::duration<RepT, PeriodT> const &rel_time
);
template <class RepT, class PeriodT, class PredicateT>
bool wait_for (
std::unique_lock<mutex>& lock,
std::chrono::duration<RepT, PeriodT> const &rel_time,
PredicateT pred
);
private:
CONDITION_VARIABLE m_native;
};
};
}

View File

@ -8,10 +8,9 @@
#pragma once
#include "condition_variable.hpp"
#include "mutex.hpp"
#include <atomic>
#include <mutex>
#include <condition_variable>
namespace cruft::thread {
@ -49,8 +48,8 @@ namespace cruft::thread {
private:
std::atomic<int> m_value;
mutex m_mutex;
condition_variable m_cv;
std::mutex m_mutex;
std::condition_variable m_cv;
};
}

View File

@ -8,10 +8,10 @@
#pragma once
#include "mutex.hpp"
#include "condition_variable.hpp"
#include <atomic>
#include <mutex>
#include <condition_variable>
namespace cruft::thread {
/// a fire-once event that users can wait upon. if already fired then
@ -34,7 +34,7 @@ namespace cruft::thread {
private:
std::atomic<bool> fired;
::cruft::thread::mutex m_mutex;
::cruft::thread::condition_variable m_condition;
std::mutex m_mutex;
std::condition_variable m_condition;
};
}

View File

@ -1,4 +0,0 @@
#pragma once
namespace cruft::thread {
}

View File

@ -6,16 +6,15 @@
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_THREAD_MONITOR_HPP
#define CRUFT_UTIL_THREAD_MONITOR_HPP
#pragma once
#include "mutex.hpp"
#include <utility>
#include <functional>
#include <mutex>
#include <utility>
namespace cruft::thread {
template <typename ValueT, typename MutexT = cruft::thread::mutex>
template <typename ValueT, typename MutexT = std::mutex>
class monitor {
public:
template <typename ...Args>
@ -48,5 +47,3 @@ namespace cruft::thread {
ValueT m_value;
};
};
#endif

View File

@ -1,19 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2019 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "../platform.hpp"
#if defined(PLATFORM_LINUX)
#include "mutex_std.hpp"
#elif defined(PLATFORM_WIN32)
#include "mutex_win32.hpp"
#else
#error "Unsupported mutex platform"
#endif

View File

@ -1,17 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2019 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include <mutex>
namespace cruft::thread {
inline namespace std {
using mutex = ::std::mutex;
}
}

View File

@ -1,39 +0,0 @@
#include "mutex.hpp"
using cruft::thread::win32::mutex;
///////////////////////////////////////////////////////////////////////////////
mutex::~mutex ()
{
DeleteCriticalSection (&m_section);
}
///////////////////////////////////////////////////////////////////////////////
void mutex::lock (void)
{
EnterCriticalSection (&m_section);
}
//-----------------------------------------------------------------------------
void mutex::unlock (void)
{
LeaveCriticalSection (&m_section);
}
//-----------------------------------------------------------------------------
bool mutex::try_lock (void)
{
return TryEnterCriticalSection (&m_section);
}
///////////////////////////////////////////////////////////////////////////////
CRITICAL_SECTION&
mutex::native_handle (void)
{
return m_section;
}

View File

@ -1,41 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2019 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "../win32/handle.hpp"
#include "../win32/windows.hpp"
// Include the std mutex header so we can get access to expected
// functionality like std::lock_guard.
#include <mutex>
namespace cruft::thread {
inline namespace win32 {
class mutex {
public:
constexpr mutex () noexcept
: m_section {}
{
InitializeCriticalSection (&m_section);
}
mutex (mutex const&) = delete;
~mutex ();
void lock (void);
void unlock (void);
bool try_lock (void);
CRITICAL_SECTION& native_handle (void);
private:
CRITICAL_SECTION m_section;
};
};
}

View File

@ -1,19 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2019 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "../platform.hpp"
#if defined(PLATFORM_LINUX)
#include "thread_std.hpp"
#elif defined(PLATFORM_WIN32)
#include "thread_win32.hpp"
#else
#error "Unsupported threading system"
#endif

View File

@ -1,18 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2019 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include <thread>
namespace cruft::thread {
inline namespace std {
using thread = ::std::thread;
namespace this_thread = ::std::this_thread;
}
}

View File

@ -1,47 +0,0 @@
#include "thread_win32.hpp"
using cruft::thread::win32::thread;
///////////////////////////////////////////////////////////////////////////////
thread::thread () noexcept
{ ; }
//-----------------------------------------------------------------------------
thread::thread (thread &&rhs) noexcept
{
std::swap (m_handle, rhs.m_handle);
}
//-----------------------------------------------------------------------------
thread&
thread::operator= (thread &&rhs) noexcept
{
std::swap (m_handle, rhs.m_handle);
return *this;
}
///////////////////////////////////////////////////////////////////////////////
void thread::join ()
{
WaitForSingleObject (m_handle, INFINITE);
}
///////////////////////////////////////////////////////////////////////////////
unsigned int thread::hardware_concurrency (void) noexcept
{
SYSTEM_INFO res;
GetNativeSystemInfo (&res);
return res.dwNumberOfProcessors;
}
///////////////////////////////////////////////////////////////////////////////
void cruft::thread::win32::this_thread::yield (void) noexcept
{
Sleep (0);
}

View File

@ -1,157 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2019 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "../win32/handle.hpp"
#include "../win32/windows.hpp"
#include "../win32/except.hpp"
#include <chrono>
namespace cruft::thread {
inline namespace win32 {
namespace detail {
template <class T>
std::decay_t<T>
decay_copy (T&& v)
{
return std::forward<T>(v);
}
template <typename FunctionT, typename ...ArgsT>
class dispatcher {
public:
dispatcher (FunctionT &&func, ArgsT &&...args)
: m_func (std::forward<FunctionT> (func))
, m_args (std::forward<ArgsT> (args)...)
{ ; }
void run (void)
{
return _run (
std::make_index_sequence<sizeof...(ArgsT)> {}
);
}
private:
template <std::size_t... S>
void _run (std::index_sequence <S...>)
{
std::invoke (
decay_copy (std::forward<FunctionT> (m_func)),
decay_copy (std::forward<ArgsT> (std::get<S> (m_args)))...
);
}
FunctionT m_func;
std::tuple<ArgsT...> m_args;
};
template <typename DispatcherT>
DWORD WINAPI run (LPVOID arg)
{
auto *obj = reinterpret_cast<DispatcherT*> (arg);
try {
obj->run ();
return 0;
} catch (...) {
delete obj;
throw;
}
}
};
struct thread {
using id = ::cruft::win32::handle::native_type;
thread () noexcept;
thread (thread &&) noexcept;
template <typename FunctionT, typename... ArgsT>
thread (FunctionT &&func, ArgsT&&...args)
{
using dispatch_t = detail::dispatcher<FunctionT,ArgsT...>;
auto data = std::make_unique<dispatch_t> (
std::forward<FunctionT> (func),
std::forward<ArgsT> (args)...
);
m_handle.reset (
CreateThread (
nullptr, 0,
detail::run<dispatch_t>,
static_cast<void*> (data.get ()),
0,
nullptr
)
);
if (!m_handle)
throw std::system_error (
cruft::win32::error::last_code (),
std::generic_category ()
);
data.release ();
}
thread (thread const&) = delete;
thread& operator= (thread&&) noexcept;
void join (void);
static unsigned int hardware_concurrency () noexcept;
private:
::cruft::win32::handle m_handle;
};
namespace this_thread {
void yield (void) noexcept;
thread::id get_id (void) noexcept;
template <class Rep, class Period>
void sleep_for (
std::chrono::duration<Rep, Period> const& sleep_duration
) {
auto remain = std::chrono::duration_cast<std::chrono::milliseconds> (
sleep_duration
).count ();
while (remain > 0) {
auto const step = cruft::min (remain, INFINITE - 1);
Sleep (remain);
remain -= step;
}
}
template <class ClockT, class DurationT>
void
sleep_until (std::chrono::time_point<ClockT, DurationT> const& sleep_time)
{
if (ClockT::is_steady)
return sleep_for (sleep_time - ClockT::now ());
for (auto now = ClockT::now (); now < sleep_time; now = ClockT::now ())
sleep_for (sleep_time - now);
}
template <class Clock, class Duration>
void sleep_until (std::chrono::time_point<Clock,Duration> const& sleep_time);
}
};
}

View File

@ -8,13 +8,13 @@
#include "time.hpp"
#include "thread/thread.hpp"
#include <chrono>
#include <thread>
///////////////////////////////////////////////////////////////////////////////
void
cruft::sleep (uint64_t ns)
{
cruft::thread::this_thread::sleep_for (std::chrono::nanoseconds (ns));
std::this_thread::sleep_for (std::chrono::nanoseconds (ns));
}