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:
parent
e4eb234889
commit
e8f23a349e
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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 (
|
||||
|
@ -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 (
|
||||
|
@ -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 ();
|
||||
|
@ -1,4 +0,0 @@
|
||||
int main ()
|
||||
{
|
||||
|
||||
}
|
@ -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");
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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 ();
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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 ();
|
||||
|
@ -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 ();
|
||||
}
|
@ -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),
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
};
|
||||
};
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace cruft::thread {
|
||||
}
|
@ -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
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
};
|
||||
};
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user