110 lines
1.5 KiB
C++
Executable File
110 lines
1.5 KiB
C++
Executable File
// 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
|