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)
|
if (LINUX)
|
||||||
list (APPEND UTIL_FILES
|
list (APPEND UTIL_FILES
|
||||||
thread/thread_std.hpp
|
|
||||||
thread/event_futex.cpp
|
thread/event_futex.cpp
|
||||||
thread/flag_futex.cpp
|
thread/flag_futex.cpp
|
||||||
rand/system_linux.cpp
|
rand/system_linux.cpp
|
||||||
@ -174,41 +173,30 @@ endif ()
|
|||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
list (APPEND UTIL_FILES
|
list (APPEND UTIL_FILES
|
||||||
thread/condition_variable.hpp
|
|
||||||
thread/event.hpp
|
thread/event.hpp
|
||||||
thread/flag.hpp
|
thread/flag.hpp
|
||||||
thread/mutex.hpp
|
|
||||||
thread/primitive.hpp
|
thread/primitive.hpp
|
||||||
thread/semaphore.hpp
|
thread/semaphore.hpp
|
||||||
thread/thread.hpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (LINUX)
|
if (LINUX)
|
||||||
list (APPEND UTIL_FILES
|
list (APPEND UTIL_FILES
|
||||||
thread/condition_variable_std.hpp
|
|
||||||
thread/event_futex.cpp
|
thread/event_futex.cpp
|
||||||
thread/event_futex.hpp
|
thread/event_futex.hpp
|
||||||
thread/semaphore_linux.hpp
|
thread/semaphore_linux.hpp
|
||||||
thread/semaphore_linux.cpp
|
thread/semaphore_linux.cpp
|
||||||
thread/flag_futex.cpp
|
thread/flag_futex.cpp
|
||||||
thread/flag_futex.hpp
|
thread/flag_futex.hpp
|
||||||
thread/mutex_std.hpp
|
|
||||||
)
|
)
|
||||||
elseif (WIN32)
|
elseif (WIN32)
|
||||||
list (APPEND UTIL_FILES
|
list (APPEND UTIL_FILES
|
||||||
thread/condition_variable_win32.cpp
|
|
||||||
thread/condition_variable_win32.hpp
|
|
||||||
thread/event_std.cpp
|
thread/event_std.cpp
|
||||||
thread/event_std.hpp
|
thread/event_std.hpp
|
||||||
thread/event_win32.cpp
|
thread/event_win32.cpp
|
||||||
thread/mutex_win32.cpp
|
|
||||||
thread/mutex_win32.hpp
|
|
||||||
thread/semaphore_win32.hpp
|
thread/semaphore_win32.hpp
|
||||||
thread/semaphore_win32.cpp
|
thread/semaphore_win32.cpp
|
||||||
thread/flag_std.cpp
|
thread/flag_std.cpp
|
||||||
thread/flag_std.hpp
|
thread/flag_std.hpp
|
||||||
thread/thread_win32.cpp
|
|
||||||
thread/thread_win32.hpp
|
|
||||||
)
|
)
|
||||||
else ()
|
else ()
|
||||||
message (FATAL_ERROR "Unsupported thread platform")
|
message (FATAL_ERROR "Unsupported thread platform")
|
||||||
@ -537,7 +525,6 @@ list (
|
|||||||
thread/flag.hpp
|
thread/flag.hpp
|
||||||
thread/monitor.cpp
|
thread/monitor.cpp
|
||||||
thread/monitor.hpp
|
thread/monitor.hpp
|
||||||
thread/mutex.hpp
|
|
||||||
thread/ticketlock.cpp
|
thread/ticketlock.cpp
|
||||||
thread/ticketlock.hpp
|
thread/ticketlock.hpp
|
||||||
thread/spinlock.cpp
|
thread/spinlock.cpp
|
||||||
@ -740,15 +727,12 @@ if (TESTS)
|
|||||||
stringid
|
stringid
|
||||||
stringcache
|
stringcache
|
||||||
strongdef
|
strongdef
|
||||||
thread/condition_variable
|
|
||||||
thread/event
|
thread/event
|
||||||
thread/flag
|
thread/flag
|
||||||
thread/monitor
|
thread/monitor
|
||||||
thread/mutex
|
|
||||||
thread/semaphore
|
thread/semaphore
|
||||||
thread/spinlock
|
thread/spinlock
|
||||||
thread/ticketlock
|
thread/ticketlock
|
||||||
thread/thread
|
|
||||||
time/8601
|
time/8601
|
||||||
traits
|
traits
|
||||||
tuple/index
|
tuple/index
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
A simple cross-platform C++ utility library.
|
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
|
=== Environment Variables
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ queue::default_parallelism (void) noexcept
|
|||||||
LOG_ERROR ("Unable to parse JOB_THREADS. Using the default");
|
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);
|
CHECK_GE (m_tasks.finishing.capacity (), thread_count);
|
||||||
|
|
||||||
for (auto &t: m_threads)
|
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/flag.hpp"
|
||||||
#include "../thread/monitor.hpp"
|
#include "../thread/monitor.hpp"
|
||||||
#include "../thread/semaphore.hpp"
|
#include "../thread/semaphore.hpp"
|
||||||
#include "../thread/thread.hpp"
|
|
||||||
#include "../thread/ticketlock.hpp"
|
#include "../thread/ticketlock.hpp"
|
||||||
|
|
||||||
#include "../parallel/queue.hpp"
|
#include "../parallel/queue.hpp"
|
||||||
@ -25,6 +24,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
namespace cruft::job {
|
namespace cruft::job {
|
||||||
@ -201,10 +201,10 @@ namespace cruft::job {
|
|||||||
|
|
||||||
thread::semaphore m_pending;
|
thread::semaphore m_pending;
|
||||||
|
|
||||||
std::vector<thread::thread> m_threads;
|
std::vector<std::thread> m_threads;
|
||||||
|
|
||||||
thread::semaphore m_doomed;
|
thread::semaphore m_doomed;
|
||||||
thread::thread m_reaper;
|
std::thread m_reaper;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#include "job/queue.hpp"
|
#include "job/queue.hpp"
|
||||||
#include "thread/thread.hpp"
|
|
||||||
#include "tap.hpp"
|
#include "tap.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -33,7 +32,7 @@ main (void)
|
|||||||
std::atomic<int> count = 0;
|
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::vector<cruft::job::queue::cookie> cookies;
|
||||||
std::generate_n (std::back_inserter (cookies), INNER, [&] () {
|
std::generate_n (std::back_inserter (cookies), INNER, [&] () {
|
||||||
return q.submit (
|
return q.submit (
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
#include "parallel/queue.hpp"
|
#include "parallel/queue.hpp"
|
||||||
#include "thread/flag.hpp"
|
#include "thread/flag.hpp"
|
||||||
#include "thread/semaphore.hpp"
|
#include "thread/semaphore.hpp"
|
||||||
#include "thread/thread.hpp"
|
|
||||||
|
|
||||||
#include "tap.hpp"
|
#include "tap.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
static constexpr uint32_t slots = 4;
|
static constexpr uint32_t slots = 4;
|
||||||
static constexpr int parallelism = 8;
|
static constexpr int parallelism = 8;
|
||||||
@ -65,8 +66,8 @@ main ()
|
|||||||
|
|
||||||
// start n consumers, and n producers that fill an array with integers
|
// start n consumers, and n producers that fill an array with integers
|
||||||
std::vector<int> dst (parallelism * chunk_size);
|
std::vector<int> dst (parallelism * chunk_size);
|
||||||
std::vector<cruft::thread::thread> consumers;
|
std::vector<std::thread> consumers;
|
||||||
std::vector<cruft::thread::thread> producers;
|
std::vector<std::thread> producers;
|
||||||
|
|
||||||
for (int i = 0; i < parallelism; ++i) {
|
for (int i = 0; i < parallelism; ++i) {
|
||||||
consumers.emplace_back (
|
consumers.emplace_back (
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#include "thread/flag.hpp"
|
#include "thread/flag.hpp"
|
||||||
#include "thread/thread.hpp"
|
|
||||||
#include "parallel/stack.hpp"
|
#include "parallel/stack.hpp"
|
||||||
|
|
||||||
#include "tap.hpp"
|
#include "tap.hpp"
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
int main ()
|
int main ()
|
||||||
@ -57,8 +57,8 @@ int main ()
|
|||||||
static int constexpr ITERATIONS = 8 * 1024;
|
static int constexpr ITERATIONS = 8 * 1024;
|
||||||
cruft::parallel::stack<int> store (8);
|
cruft::parallel::stack<int> store (8);
|
||||||
cruft::thread::flag ev;
|
cruft::thread::flag ev;
|
||||||
std::vector<cruft::thread::thread> contestants;
|
std::vector<std::thread> contestants;
|
||||||
for (unsigned i = 0; i < cruft::thread::thread::hardware_concurrency () + 1; ++i)
|
for (unsigned i = 0; i < std::thread::hardware_concurrency () + 1; ++i)
|
||||||
contestants.emplace_back (fight, std::ref (store), std::ref (ev), ITERATIONS);
|
contestants.emplace_back (fight, std::ref (store), std::ref (ev), ITERATIONS);
|
||||||
|
|
||||||
ev.notify_all ();
|
ev.notify_all ();
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
int main ()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
@ -1,9 +1,9 @@
|
|||||||
#include "thread/event.hpp"
|
#include "thread/event.hpp"
|
||||||
#include "thread/thread.hpp"
|
|
||||||
|
|
||||||
#include "tap.hpp"
|
#include "tap.hpp"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -20,14 +20,14 @@ main ()
|
|||||||
std::atomic<int> val = 0;
|
std::atomic<int> val = 0;
|
||||||
cruft::thread::event a;
|
cruft::thread::event a;
|
||||||
|
|
||||||
cruft::thread::thread t ([&] () {
|
std::thread t ([&] () {
|
||||||
a.wait ();
|
a.wait ();
|
||||||
++val;
|
++val;
|
||||||
});
|
});
|
||||||
|
|
||||||
// block for hopefully long enough to allow the above thread to change
|
// block for hopefully long enough to allow the above thread to change
|
||||||
// the value of the integer.
|
// 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");
|
tap.expect_eq (val, 0, "waiting actually blocks");
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
#include "thread/flag.hpp"
|
#include "thread/flag.hpp"
|
||||||
#include "thread/thread.hpp"
|
|
||||||
|
|
||||||
#include "tap.hpp"
|
#include "tap.hpp"
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main ()
|
main ()
|
||||||
@ -12,12 +13,12 @@ main ()
|
|||||||
cruft::thread::flag f;
|
cruft::thread::flag f;
|
||||||
std::atomic<int> value = 0;
|
std::atomic<int> value = 0;
|
||||||
|
|
||||||
cruft::thread::thread t1 ([&] () {
|
std::thread t1 ([&] () {
|
||||||
f.wait ();
|
f.wait ();
|
||||||
value = 1;
|
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");
|
tap.expect_eq (value, 0, "value hasn't been set during wait");
|
||||||
f.notify_all ();
|
f.notify_all ();
|
||||||
@ -25,12 +26,12 @@ main ()
|
|||||||
t1.join ();
|
t1.join ();
|
||||||
tap.expect_eq (value, 1, "value has been changed after wait");
|
tap.expect_eq (value, 1, "value has been changed after wait");
|
||||||
|
|
||||||
cruft::thread::thread t2 ([&] () {
|
std::thread t2 ([&] () {
|
||||||
f.wait ();
|
f.wait ();
|
||||||
value = 2;
|
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");
|
tap.expect_eq (value, 2, "second wait didn't appear to block");
|
||||||
t2.join ();
|
t2.join ();
|
||||||
|
|
||||||
@ -59,13 +60,13 @@ main ()
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<cruft::thread::thread> workers;
|
std::vector<std::thread> workers;
|
||||||
std::generate_n (
|
std::generate_n (
|
||||||
std::back_inserter (workers),
|
std::back_inserter (workers),
|
||||||
parallelism,
|
parallelism,
|
||||||
[&, i = 0] () mutable
|
[&, i = 0] () mutable
|
||||||
{
|
{
|
||||||
return cruft::thread::thread { func, i++ };
|
return std::thread { func, i++ };
|
||||||
});
|
});
|
||||||
|
|
||||||
for (auto &t: workers)
|
for (auto &t: workers)
|
||||||
|
@ -9,11 +9,11 @@
|
|||||||
#include "thread/event.hpp"
|
#include "thread/event.hpp"
|
||||||
#include "thread/monitor.hpp"
|
#include "thread/monitor.hpp"
|
||||||
#include "thread/semaphore.hpp"
|
#include "thread/semaphore.hpp"
|
||||||
#include "thread/thread.hpp"
|
|
||||||
|
|
||||||
#include "tap.hpp"
|
#include "tap.hpp"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -49,8 +49,8 @@ main ()
|
|||||||
auto &enter = obj->enter;
|
auto &enter = obj->enter;
|
||||||
auto &leave = obj->leave;
|
auto &leave = obj->leave;
|
||||||
|
|
||||||
cruft::thread::thread t1 ([&] () { obj->inc (); });
|
std::thread t1 ([&] () { obj->inc (); });
|
||||||
cruft::thread::thread t2 ([&] () { obj->inc (); });
|
std::thread t2 ([&] () { obj->inc (); });
|
||||||
|
|
||||||
tap.expect_eq (value, 0, "wrapped class was left initialised");
|
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/semaphore.hpp"
|
||||||
#include "thread/flag.hpp"
|
#include "thread/flag.hpp"
|
||||||
#include "thread/thread.hpp"
|
|
||||||
#include "thread/mutex.hpp"
|
|
||||||
|
|
||||||
#include "tap.hpp"
|
#include "tap.hpp"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
void
|
void
|
||||||
@ -35,7 +36,7 @@ main ()
|
|||||||
// the spawned thread attempts to double acquire a semaphore with
|
// the spawned thread attempts to double acquire a semaphore with
|
||||||
// only one available and so should get blocked immediately.
|
// only one available and so should get blocked immediately.
|
||||||
std::atomic<int> test = 0;
|
std::atomic<int> test = 0;
|
||||||
cruft::thread::thread t ([&] () {
|
std::thread t ([&] () {
|
||||||
sem.lock ();
|
sem.lock ();
|
||||||
sem.lock ();
|
sem.lock ();
|
||||||
test = 1;
|
test = 1;
|
||||||
@ -44,7 +45,7 @@ main ()
|
|||||||
// wait until we know the thread should have been blocked. it should
|
// wait until we know the thread should have been blocked. it should
|
||||||
// not have touched the 'test' variable at this point.
|
// not have touched the 'test' variable at this point.
|
||||||
while (sem.value () > 0)
|
while (sem.value () > 0)
|
||||||
cruft::thread::this_thread::yield ();
|
std::this_thread::yield ();
|
||||||
|
|
||||||
tap.expect_eq (test, 0, "locking blocks in foreign thread");
|
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;
|
constexpr int iterations = 1 << 16;
|
||||||
std::vector<cruft::thread::thread> threads;
|
std::vector<std::thread> threads;
|
||||||
|
|
||||||
cruft::thread::semaphore sem (0);
|
cruft::thread::semaphore sem (0);
|
||||||
|
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
|
|
||||||
#include "thread/flag.hpp"
|
#include "thread/flag.hpp"
|
||||||
#include "thread/spinlock.hpp"
|
#include "thread/spinlock.hpp"
|
||||||
#include "thread/thread.hpp"
|
|
||||||
|
|
||||||
#include "tap.hpp"
|
#include "tap.hpp"
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -38,14 +38,14 @@ main ()
|
|||||||
l.unlock ();
|
l.unlock ();
|
||||||
tap.expect (true, "unlocked without contention");
|
tap.expect (true, "unlocked without contention");
|
||||||
|
|
||||||
if (cruft::thread::thread::hardware_concurrency () < 2) {
|
if (std::thread::hardware_concurrency () < 2) {
|
||||||
tap.skip ("n-way fight");
|
tap.skip ("n-way fight");
|
||||||
} else {
|
} else {
|
||||||
constexpr int iterations = 1 << 12;
|
constexpr int iterations = 1 << 12;
|
||||||
cruft::thread::flag start_flag;
|
cruft::thread::flag start_flag;
|
||||||
|
|
||||||
std::vector<cruft::thread::thread> contestants;
|
std::vector<std::thread> contestants;
|
||||||
for (unsigned i = 0; i < cruft::thread::thread::hardware_concurrency (); ++i)
|
for (unsigned i = 0; i < std::thread::hardware_concurrency (); ++i)
|
||||||
contestants.emplace_back (fight, std::ref (start_flag), std::ref (l), iterations);
|
contestants.emplace_back (fight, std::ref (start_flag), std::ref (l), iterations);
|
||||||
|
|
||||||
start_flag.notify_all ();
|
start_flag.notify_all ();
|
||||||
@ -53,7 +53,7 @@ main ()
|
|||||||
for (auto &t: contestants)
|
for (auto &t: contestants)
|
||||||
t.join ();
|
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 ();
|
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/flag.hpp"
|
||||||
#include "thread/ticketlock.hpp"
|
#include "thread/ticketlock.hpp"
|
||||||
#include "thread/thread.hpp"
|
|
||||||
#include "thread/mutex.hpp"
|
|
||||||
|
|
||||||
#include "tap.hpp"
|
#include "tap.hpp"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
using ffs_t = std::chrono::high_resolution_clock;
|
using ffs_t = std::chrono::high_resolution_clock;
|
||||||
@ -44,7 +45,7 @@ main ()
|
|||||||
l.unlock ();
|
l.unlock ();
|
||||||
tap.expect (true, "unlocked without contention");
|
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");
|
tap.skip ("reasonably fair under contention");
|
||||||
} else {
|
} else {
|
||||||
// measure fairness under contention is below some threshold
|
// measure fairness under contention is below some threshold
|
||||||
@ -63,7 +64,7 @@ main ()
|
|||||||
|
|
||||||
ffs_t::time_point a_finish, b_finish;
|
ffs_t::time_point a_finish, b_finish;
|
||||||
|
|
||||||
cruft::thread::thread a (
|
std::thread a (
|
||||||
fight,
|
fight,
|
||||||
std::ref (start_flag),
|
std::ref (start_flag),
|
||||||
std::ref (l),
|
std::ref (l),
|
||||||
@ -71,7 +72,7 @@ main ()
|
|||||||
std::ref (a_finish)
|
std::ref (a_finish)
|
||||||
);
|
);
|
||||||
|
|
||||||
cruft::thread::thread b (
|
std::thread b (
|
||||||
fight,
|
fight,
|
||||||
std::ref (start_flag),
|
std::ref (start_flag),
|
||||||
std::ref (l),
|
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
|
#pragma once
|
||||||
|
|
||||||
#include "condition_variable.hpp"
|
|
||||||
#include "mutex.hpp"
|
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
|
||||||
namespace cruft::thread {
|
namespace cruft::thread {
|
||||||
@ -49,8 +48,8 @@ namespace cruft::thread {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<int> m_value;
|
std::atomic<int> m_value;
|
||||||
mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
condition_variable m_cv;
|
std::condition_variable m_cv;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "mutex.hpp"
|
|
||||||
#include "condition_variable.hpp"
|
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
|
||||||
namespace cruft::thread {
|
namespace cruft::thread {
|
||||||
/// a fire-once event that users can wait upon. if already fired then
|
/// a fire-once event that users can wait upon. if already fired then
|
||||||
@ -34,7 +34,7 @@ namespace cruft::thread {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<bool> fired;
|
std::atomic<bool> fired;
|
||||||
::cruft::thread::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
::cruft::thread::condition_variable m_condition;
|
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>
|
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CRUFT_UTIL_THREAD_MONITOR_HPP
|
#pragma once
|
||||||
#define CRUFT_UTIL_THREAD_MONITOR_HPP
|
|
||||||
|
|
||||||
#include "mutex.hpp"
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
|
||||||
namespace cruft::thread {
|
namespace cruft::thread {
|
||||||
template <typename ValueT, typename MutexT = cruft::thread::mutex>
|
template <typename ValueT, typename MutexT = std::mutex>
|
||||||
class monitor {
|
class monitor {
|
||||||
public:
|
public:
|
||||||
template <typename ...Args>
|
template <typename ...Args>
|
||||||
@ -48,5 +47,3 @@ namespace cruft::thread {
|
|||||||
ValueT m_value;
|
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 "time.hpp"
|
||||||
|
|
||||||
#include "thread/thread.hpp"
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
void
|
void
|
||||||
cruft::sleep (uint64_t ns)
|
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