diff --git a/CMakeLists.txt b/CMakeLists.txt
index ad927ed6..df3aa574 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@ cmake_policy(SET CMP0017 NEW) # need include() with .cmake
project(pip)
set(pip_MAJOR 2)
set(pip_MINOR 31)
-set(pip_REVISION 0)
+set(pip_REVISION 1)
set(pip_SUFFIX )
set(pip_COMPANY SHS)
set(pip_DOMAIN org.SHS)
diff --git a/libs/main/io_devices/pifile.h b/libs/main/io_devices/pifile.h
index 9270ae09..2cb9c036 100644
--- a/libs/main/io_devices/pifile.h
+++ b/libs/main/io_devices/pifile.h
@@ -85,6 +85,7 @@ public:
};
//! Constructs a file with path "path" and open mode "mode"
+ //! If "path" is not empty then open file
explicit PIFile(const PIString & path, DeviceMode mode = ReadWrite);
diff --git a/libs/main/thread/pithreadmodule.h b/libs/main/thread/pithreadmodule.h
index cb1128e1..18706e05 100644
--- a/libs/main/thread/pithreadmodule.h
+++ b/libs/main/thread/pithreadmodule.h
@@ -26,7 +26,8 @@
#include "pitimer.h"
#include "pipipelinethread.h"
#include "pigrabberbase.h"
-#include "pithreadpoolexecutor.h"
#include "piconditionvar.h"
+#include "pithreadpoolexecutor.h"
+#include "pithreadpoolloop.h"
#endif // PITHREADMODULE_H
diff --git a/libs/main/thread/pithreadpoolloop.cpp b/libs/main/thread/pithreadpoolloop.cpp
new file mode 100644
index 00000000..b829469b
--- /dev/null
+++ b/libs/main/thread/pithreadpoolloop.cpp
@@ -0,0 +1,130 @@
+/*
+ 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();
+}
diff --git a/libs/main/thread/pithreadpoolloop.h b/libs/main/thread/pithreadpoolloop.h
new file mode 100644
index 00000000..30938d66
--- /dev/null
+++ b/libs/main/thread/pithreadpoolloop.h
@@ -0,0 +1,69 @@
+/*! @file pithreadpoolloop.h
+ * @brief Thread pool loop
+ *
+ * This file declare thread class and some wait functions
+*/
+/*
+ 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 .
+*/
+
+#ifndef PITHREADPOOLLOOP_H
+#define PITHREADPOOLLOOP_H
+
+#include "pivector.h"
+
+class PIThread;
+
+class PIP_EXPORT PIThreadPoolLoop {
+public:
+
+ //! Contructs thread pool with threads count "thread_cnt".
+ //! If "thread_cnt" = -1 then system processors count used
+ PIThreadPoolLoop(int thread_cnt = -1);
+
+ virtual ~PIThreadPoolLoop();
+
+ //! Set threads function to "f" with format [](int){...}
+ void setFunction(std::function f);
+
+ //! Wait for all threads stop
+ void wait();
+
+ //! Start functions execution with integer argument range
+ //! from "index_start" to "index_start + index_count - 1"
+ void start(int index_start, int index_count);
+
+ //! Start functions execution with integer argument range
+ //! from "index_start" to "index_start + index_count - 1"
+ //! and wait for finish
+ void exec(int index_start, int index_count);
+
+ //! Start functions "f" execution with integer argument range
+ //! from "index_start" to "index_start + index_count - 1"
+ //! and wait for finish
+ void exec(int index_start, int index_count, std::function f);
+
+private:
+ PIVector threads;
+ std::function func;
+ std::atomic_int counter;
+
+};
+
+
+#endif
diff --git a/main.cpp b/main.cpp
index 1ed2e829..1779d4dd 100644
--- a/main.cpp
+++ b/main.cpp
@@ -3,6 +3,20 @@
int main(int argc, char * argv[]) {
+ PIVector data(10, [](int i)->int{return i;});
+
+ piCout << data;
+
+ PIThreadPoolLoop pool;
+ pool.setFunction([&](int i){
+ data[i] = data[i] + 10;
+ });
+ pool.exec(0, data.size());
+
+ piCout << data;
+
+ return 0;
+
PIVector x(20, [](int i) {return i;});
piCout << x;
piCout << x.any([](int v) {return v == 10;});