flatten 20260225
This commit is contained in:
109
tjp/core/threads/Parallel.cpp
Executable file
109
tjp/core/threads/Parallel.cpp
Executable file
@@ -0,0 +1,109 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#include "Parallel.hpp"
|
||||
#include <limits>
|
||||
|
||||
namespace tjp::core::threads {
|
||||
|
||||
|
||||
Parallel::Parallel(int max, int free)
|
||||
{
|
||||
start(max, free);
|
||||
}
|
||||
|
||||
Parallel::~Parallel()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void Parallel::start(int max, int free)
|
||||
{
|
||||
auto lock = lock_of(mutex);
|
||||
if (running)
|
||||
return;
|
||||
|
||||
running = true;
|
||||
auto n_ =
|
||||
std::max(
|
||||
1,
|
||||
std::min(
|
||||
max,
|
||||
(int)std::thread::hardware_concurrency() - free
|
||||
)
|
||||
);
|
||||
|
||||
n = n_;
|
||||
debug_assert(n > 0 && n <= max);
|
||||
|
||||
threads = new std::thread[n];
|
||||
|
||||
for (auto m=0; m<n; m++)
|
||||
{
|
||||
threads[m] = std::thread([this, m]() {
|
||||
execute(n, m);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Parallel::execute(size_t n, size_t m)
|
||||
{
|
||||
auto lock = lock_of(mutex);
|
||||
while (running)
|
||||
{
|
||||
event.wait(lock, [&](){
|
||||
return
|
||||
!running ||
|
||||
(signal & (SignalBit << m));
|
||||
});
|
||||
|
||||
if (!running)
|
||||
break;
|
||||
|
||||
{
|
||||
auto unlock = unlock_of(mutex);
|
||||
|
||||
f(n, m);
|
||||
}
|
||||
|
||||
signal ^= SignalBit << m;
|
||||
|
||||
event.notify_all();
|
||||
}
|
||||
|
||||
event.notify_all();
|
||||
}
|
||||
|
||||
void Parallel::run(F &&f_)
|
||||
{
|
||||
auto lock_ = lock_of(oneUser);
|
||||
auto lock = lock_of(mutex);
|
||||
|
||||
f = std::move(f_);
|
||||
signal = 0;
|
||||
for (auto i=0; i<n; ++i)
|
||||
signal |= (1 << i);
|
||||
|
||||
event.notify_all();
|
||||
|
||||
event.wait(lock, [&]() {
|
||||
return signal == 0 || !running;
|
||||
});
|
||||
}
|
||||
|
||||
void Parallel::stop()
|
||||
{
|
||||
if (!running)
|
||||
return;
|
||||
|
||||
running = false;
|
||||
signal = std::numeric_limits<Signal>::max();
|
||||
event.notify_all();
|
||||
|
||||
auto n = std::thread::hardware_concurrency();
|
||||
for (auto m=0; m<n; ++m)
|
||||
threads[m].join();
|
||||
|
||||
delete[] threads;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
9
tjp/core/threads/Parallel.h
Executable file
9
tjp/core/threads/Parallel.h
Executable file
@@ -0,0 +1,9 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp::core::threads {
|
||||
|
||||
struct Parallel;
|
||||
|
||||
} // namespace
|
||||
44
tjp/core/threads/Parallel.hpp
Executable file
44
tjp/core/threads/Parallel.hpp
Executable file
@@ -0,0 +1,44 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Parallel.h"
|
||||
#include <thread>
|
||||
|
||||
#include <tjp/core/threads/Lock.hpp>
|
||||
#include <tjp/core/threads/Atomic.h>
|
||||
#include <tjp/core/threads/TestMutex.hpp>
|
||||
#include <tjp/core/containers/Function.hpp>
|
||||
|
||||
namespace tjp::core::threads {
|
||||
|
||||
struct Parallel
|
||||
{
|
||||
size_t n;
|
||||
std::thread *threads;
|
||||
|
||||
using F = Function<void(size_t n, size_t m)>;
|
||||
F f;
|
||||
|
||||
[[no_unique_address]]
|
||||
TestMutex oneUser;
|
||||
|
||||
Event event;
|
||||
Event::Mutex mutex;
|
||||
bool running = false;
|
||||
|
||||
using Signal = u128;
|
||||
static constexpr Signal SignalBit = 1;
|
||||
Signal signal = 0;
|
||||
|
||||
Parallel(int max, int free);
|
||||
~Parallel();
|
||||
|
||||
void start(int max, int free);
|
||||
void execute(size_t n, size_t m);
|
||||
void run(F &&f_);
|
||||
void stop();
|
||||
|
||||
} ;
|
||||
|
||||
} // namespace
|
||||
140
tjp/core/threads/PinnedFutures.hpp
Executable file
140
tjp/core/threads/PinnedFutures.hpp
Executable file
@@ -0,0 +1,140 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include <tjp/core/threads/Lock.hpp>
|
||||
#include <tjp/core/threads/UnlockGuard.hpp>
|
||||
#include <tjp/core/threads/Atomic.h>
|
||||
#include <tjp/core/threads/TestMutex.hpp>
|
||||
#include <tjp/core/containers/Function.hpp>
|
||||
|
||||
#include <queue>
|
||||
|
||||
namespace tjp::core::threads {
|
||||
|
||||
|
||||
// DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT
|
||||
// DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT
|
||||
|
||||
struct PinnedFutures
|
||||
{
|
||||
std::thread thread;
|
||||
Event::Mutex mutex;
|
||||
Event event;
|
||||
std::queue<Function<void()>> events;
|
||||
bool running = false;
|
||||
|
||||
bool is_on_thread()
|
||||
{
|
||||
return thread.joinable() &&
|
||||
(std::this_thread::get_id() == thread.get_id());
|
||||
}
|
||||
|
||||
PinnedFutures(bool start_=true)
|
||||
{
|
||||
if (start_)
|
||||
start();
|
||||
}
|
||||
|
||||
~PinnedFutures()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
auto lock = lock_of(mutex);
|
||||
while (running)
|
||||
{
|
||||
if (events.empty())
|
||||
{
|
||||
event.wait(lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto fn = std::move(events.front());
|
||||
events.pop();
|
||||
|
||||
{
|
||||
auto unlock = unlock_of(mutex);
|
||||
fn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
if (running)
|
||||
return;
|
||||
|
||||
running = true;
|
||||
thread = std::thread([this]() { run(); });
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
{
|
||||
auto lock = lock_of(mutex);
|
||||
running = false;
|
||||
}
|
||||
event.notify_all();
|
||||
if (thread.joinable())
|
||||
thread.join();
|
||||
}
|
||||
|
||||
template<typename V>
|
||||
Future<V> on_(Future<V> &f0)
|
||||
{
|
||||
Promise<V> p;
|
||||
|
||||
auto swizzle = f0.then([this, p](auto &&f) {
|
||||
auto lock = lock_of(mutex);
|
||||
events.push([p, f=std::move(f)]() {
|
||||
auto p_ = p;
|
||||
auto f_ = f;
|
||||
p_.consume([&](auto &&f) { return f.get(); }, f_);
|
||||
});
|
||||
|
||||
event.notify_one();
|
||||
});
|
||||
|
||||
return p.get_future().then([swizzle](auto &&f1) {
|
||||
return f1.get();
|
||||
});
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
auto run_(F &&f)
|
||||
{
|
||||
using R = decltype(f());
|
||||
Promise<R> p;
|
||||
|
||||
{
|
||||
auto lock = lock_of(mutex);
|
||||
events.push([&]() { p.consume(f); });
|
||||
event.notify_one();
|
||||
}
|
||||
|
||||
return p.get_future().get();
|
||||
}
|
||||
|
||||
template<typename V>
|
||||
Future<V> on(Future<V> &f)
|
||||
{
|
||||
return on_(f);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
auto run(F &&f)
|
||||
{
|
||||
if (is_on_thread())
|
||||
return f();
|
||||
|
||||
return run_(std::forward<F>(f));
|
||||
}
|
||||
|
||||
} ;
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user