/* PIP - Platform Independent Primitives Thread pool loop Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "pithreadpoolloop.h" #include "pisysteminfo.h" #include "pithread.h" /*! \class PIThreadPoolLoop * \brief Thread class * \details This class allow you parallelize loop. * * \section PIThreadPoolLoop_sec0 Usage * This class designed to replace "for(;;)" statement in very simple way. * In constructor several threads created, then by "setFunction()" method * you should pass body of your loop, and then call "start()" or "exec()". * Every thread take loop counter and execute your function until all * counter range is passed. * * Example: \code{.cpp} PIVector data(10, [](int i)->int{return i;}); piCout << data; // {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} PIThreadPoolLoop pool; pool.exec(0, data.size(), [&](int i){ // parallel analogue "for (int i = 0; i < data.size(); i++)" data[i] = data[i] + 10; }); piCout << data; // {10, 11, 12, 13, 14, 15, 16, 17, 18, 19} \endcode * * Equivalent to: \code{.cpp} PIVector data(10, [](int i)->int{return i;}); piCout << data; // {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} pool.setFunction([&](int i){ data[i] = data[i] + 10; }); pool.exec(0, data.size()); piCout << data; // {10, 11, 12, 13, 14, 15, 16, 17, 18, 19} \endcode * * \section PIThreadPoolLoop_sec1 Important * Due to multithreading it`s very important to protect output data of loop body, use mutex. * Also remember that execution order is undefined and you shouldn`t use global variables in * your function. Use local variables and lambda capture. * */ PIThreadPoolLoop::PIThreadPoolLoop(int thread_cnt) { if (thread_cnt <= 0) thread_cnt = piMaxi(1, PISystemInfo::instance()->processorsCount); piForTimes (thread_cnt) { auto * t = new PIThread(); threads << t; } //piCout << "PIThreadPoolLoop" << proc_cnt << "threads"; } PIThreadPoolLoop::~PIThreadPoolLoop() { for (auto * t: threads) { t->stop(false); if (!t->waitForFinish(100)) t->terminate(); delete t; } } void PIThreadPoolLoop::setFunction(std::function f) { func = f; } void PIThreadPoolLoop::start(int index_start, int index_count) { counter = index_start; int end = index_start + index_count; for (auto * t: threads) t->start([this,end,t](){ while (1) { int cc = counter.fetch_add(1); if (cc >= end) { t->stop(false); return; } func(cc); } }); } void PIThreadPoolLoop::exec(int index_start, int index_count) { start(index_start, index_count); wait(); } void PIThreadPoolLoop::exec(int index_start, int index_count, std::function f) { setFunction(f); exec(index_start, index_count); } void PIThreadPoolLoop::wait() { for (auto * t: threads) t->waitForFinish(); }