doc ru, printf() before assert in containers

This commit is contained in:
2022-04-12 23:17:05 +03:00
parent 486fdf3dcd
commit 00830958df
18 changed files with 802 additions and 350 deletions

View File

@@ -2,8 +2,5 @@
void _() {
//! [main]
mutex.lock();
// ... your code here
mutex.unlock();
//! [main]
}

View File

@@ -440,6 +440,11 @@ public:
}
inline PIDeque<T> & insert(size_t index, const PIDeque<T> & other) {
if (other.isEmpty()) return *this;
#ifdef USE_DEBUG
if (&other == this) {
printf("error with PIDeque<%s>::insert\n", __PIP_TYPENAME__(T));
}
#endif
assert(&other != this);
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
@@ -544,6 +549,11 @@ public:
inline PIDeque<T> & append(const T & e) {return push_back(e);}
inline PIDeque<T> & append(T && e) {return push_back(std::move(e));}
inline PIDeque<T> & append(const PIDeque<T> & v) {
#ifdef USE_DEBUG
if (&v == this) {
printf("error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T));
}
#endif
assert(&v != this);
size_t ps = pid_size;
alloc(pid_size + v.pid_size, true);
@@ -615,6 +625,11 @@ public:
inline PIDeque<PIDeque<T>> reshape(size_t rows, size_t cols, int order = byRow) const {
PIDeque<PIDeque<T>> ret;
if (isEmpty()) return ret;
#ifdef USE_DEBUG
if (rows*cols != pid_size) {
printf("error with PIDeque<%s>::reshape\n", __PIP_TYPENAME__(T));
}
#endif
assert(rows*cols == pid_size);
ret.resize(rows);
if (order == byRow) {
@@ -762,6 +777,11 @@ private:
if (as != pid_rsize) {
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize))
T * p_d = (T*)(realloc((void*)(pid_data), as*sizeof(T)));
#ifdef USE_DEBUG
if (!p_d) {
printf("error with PIDeque<%s>::alloc\n", __PIP_TYPENAME__(T));
}
#endif
assert(p_d);
pid_data = p_d;
pid_rsize = as;

View File

@@ -208,6 +208,11 @@ public:
const T at(const Key & key) const {return (*this)[key];}
PIMap<Key, T> & operator <<(const PIMap<Key, T> & other) {
#ifdef USE_DEBUG
if (&other == this) {
printf("error with PIMap<%s, %s>::<<\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
}
#endif
assert(&other != this);
if (other.isEmpty()) return *this;
if (other.size() == 1) {insert(other.pim_index[0].key, other.pim_content[0]); return *this;}

View File

@@ -1199,6 +1199,11 @@ public:
//! \~\sa \a append(), \a prepend(), \a remove()
inline PIVector<T> & insert(size_t index, const PIVector<T> & v) {
if (v.isEmpty()) return *this;
#ifdef USE_DEBUG
if (&v == this) {
printf("error with PIVector<%s>::insert\n", __PIP_TYPENAME__(T));
}
#endif
assert(&v != this);
ssize_t os = piv_size - index;
alloc(piv_size + v.piv_size);
@@ -1385,6 +1390,11 @@ public:
}
inline PIVector<T> & push_back(const PIVector<T> & v) {
#ifdef USE_DEBUG
if (&v == this) {
printf("error with PIVector<%s>::push_back\n", __PIP_TYPENAME__(T));
}
#endif
assert(&v != this);
size_t ps = piv_size;
alloc(piv_size + v.piv_size);
@@ -1485,6 +1495,11 @@ public:
inline PIVector<PIVector<T>> reshape(size_t rows, size_t cols, ReshapeOrder order = byRow) const {
PIVector<PIVector<T>> ret;
if (isEmpty()) return ret;
#ifdef USE_DEBUG
if (rows*cols != piv_size) {
printf("error with PIVector<%s>::reshape\n", __PIP_TYPENAME__(T));
}
#endif
assert(rows*cols == piv_size);
ret.resize(rows);
if (order == byRow) {
@@ -1609,6 +1624,11 @@ private:
if (as == piv_rsize) return;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-piv_rsize))
T * p_d = (T*)(realloc((void*)(piv_data), as*sizeof(T)));
#ifdef USE_DEBUG
if (!p_d) {
printf("error with PIVector<%s>::alloc\n", __PIP_TYPENAME__(T));
}
#endif
assert(p_d);
piv_data = p_d;
piv_rsize = as;

View File

@@ -248,6 +248,8 @@
#ifdef NDEBUG
# undef NDEBUG
#else
# define USE_DEBUG
#endif
#ifndef assert
# define assert(x)
@@ -256,6 +258,12 @@
# define assertm(exp, msg) assert(((void)msg, exp))
#endif
#ifdef MICRO_PIP
# define __PIP_TYPENAME__(T) "?"
#else
# define __PIP_TYPENAME__(T) typeid(T).name()
#endif
#ifdef CC_GCC
# undef DEPRECATED
# define DEPRECATED __attribute__((deprecated))

View File

@@ -32,12 +32,6 @@
#include "pivector2d.h"
#include <stdio.h>
#ifdef MICRO_PIP
# define _TYPENAME_(T) "?"
#else
# define _TYPENAME_(T) typeid(T).name()
#endif
class PIString;
class PIByteArray;
@@ -394,7 +388,7 @@ inline PIByteArray & operator >>(PIByteArray & s, uchar & v) {assert(s.size() >=
template<typename T, typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray::StreamRef operator >>(PIByteArray & s, T & v) {
if (s.size() < sizeof(v)) {
printf("error with %s\n", _TYPENAME_(T));
printf("error with %s\n", __PIP_TYPENAME__(T));
assert(s.size() >= sizeof(v));
}
memcpy((void*)(&v), s.data(), sizeof(v));
@@ -430,7 +424,7 @@ template<typename T,
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
if (s.size_s() < 4) {
printf("error with PIVector<%s>\n", _TYPENAME_(T));
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
@@ -446,7 +440,7 @@ template<typename T,
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
if (s.size_s() < 4) {
printf("error with PIVector<%s>\n", _TYPENAME_(T));
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
@@ -463,7 +457,7 @@ template<typename T,
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
if (s.size_s() < 4) {
printf("error with PIDeque<%s>\n", _TYPENAME_(T));
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
@@ -479,7 +473,7 @@ template<typename T,
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
if (s.size_s() < 4) {
printf("error with PIDeque<%s>\n", _TYPENAME_(T));
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
@@ -496,7 +490,7 @@ template<typename T,
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
if (s.size_s() < 8) {
printf("error with PIVecto2Dr<%s>\n", _TYPENAME_(T));
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 8);
}
int r, c; s >> r >> c;
@@ -513,7 +507,7 @@ template<typename T,
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
if (s.size_s() < 8) {
printf("error with PIVecto2Dr<%s>\n", _TYPENAME_(T));
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 8);
}
int r,c;
@@ -581,7 +575,7 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
if (s.size_s() < 4) {
printf("error with PIVector<%s>\n", _TYPENAME_(T));
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
@@ -596,7 +590,7 @@ inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
if (s.size_s() < 4) {
printf("error with PIDeque<%s>\n", _TYPENAME_(T));
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
@@ -611,7 +605,7 @@ inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
if (s.size_s() < 8) {
printf("error with PIVecto2Dr<%s>\n", _TYPENAME_(T));
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 8);
}
int r,c;
@@ -646,7 +640,7 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIMap<Key, T> & v) {
template <typename Key, typename T>
inline PIByteArray & operator >>(PIByteArray & s, PIMap<Key, T> & v) {
if (s.size_s() < 4) {
printf("error with PIMap<%s, %s>\n", _TYPENAME_(Key), _TYPENAME_(T));
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz; v.pim_index.resize(sz);
@@ -711,7 +705,4 @@ template <typename T> T piDeserialize(const PIByteArray & data) {
}
#undef _TYPENAME_
#endif // PIBYTEARRAY_H

View File

@@ -17,22 +17,67 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \class PIMutex
* \brief Mutex
* \details
* \section PIMutex_sec0 Synopsis
* %PIMutex provides synchronization blocks between several threads.
* Using mutex guarantees execution of some code only one of threads.
* Mutex contains logic state and functions to change it: \a lock(),
* \a unlock() and \a tryLock().
*
* \section PIMutex_sec1 Usage
* Block of code that should to be executed only one thread simultaniously
* should to be started with \a lock() and ended with \a unlock().
* \snippet pimutex.cpp main
* "mutex" in this example is one for all threads.
*
* */
//! \addtogroup Thread
//! \{
//! \class PIMutex pimutex.h
//!
//! \~\brief
//! \~english Simple mutex
//! \~russian Простой мьютекс
//!
//!
//! \~\details
//! \~english \section PIMutex_sec0 Synopsis
//! \~russian \section PIMutex_sec0 Краткий обзор
//!
//! \~english
//! %PIMutex provides synchronization blocks between several threads.
//! Using mutex guarantees execution of some code only one of threads.
//! Mutex contains logic state and functions to change it: \a lock(),
//! \a unlock() and \a tryLock().
//!
//! \~russian
//!
//!
//! \~english \section PIMutex_sec0 Usage
//! \~russian \section PIMutex_sec0 Использование
//!
//! \~english
//! Block of code that should to be executed only one thread simultaniously
//! should to be started with \a lock() and finished with \a unlock().
//!
//! \~russian
//!
//! \~\code
//! mutex.lock();
//! // ... your code here
//! mutex.unlock();
//! \endcode
//! \}
//! \addtogroup Thread
//! \{
//! \class PIMutexLocker pimutex.h
//!
//! \~\brief
//! \~english %PIMutex autolocker
//! \~russian Автоблокировщик %PIMutex
//!
//!
//! \~\details
//!
//! \~english
//! When a PIMutexLocker object is created, it attempts to lock the mutex it is given, if "condition" true.
//! When control leaves the scope in which the PIMutexLocker object was created,
//! the PIMutexLocker is destructed and the mutex is released, if "condition" true.
//! If "condition" false this class do nothing.
//! The PIMutexLocker class is non-copyable.
//!
//! \~russian
//!
//! \}
#include "pimutex.h"
#include "piincludes_p.h"
@@ -68,6 +113,11 @@ PIMutex::~PIMutex() {
}
//! \~\details
//! \~english
//! If mutex is unlocked it set to locked state and returns immediate.
//! If mutex is already locked function blocks until mutex will be unlocked
//! \~russian
void PIMutex::lock() {
#if defined(WINDOWS)
EnterCriticalSection(&(PRIVATE->mutex));
@@ -79,6 +129,10 @@ void PIMutex::lock() {
}
//! \~\details
//! \~english
//! In any case this function returns immediate
//! \~russian
void PIMutex::unlock() {
#if defined(WINDOWS)
LeaveCriticalSection(&(PRIVATE->mutex));
@@ -90,6 +144,11 @@ void PIMutex::unlock() {
}
//! \~\details
//! \~english
//! If mutex is unlocked it set to locked state and returns "true" immediate.
//! If mutex is already locked function returns immediate an returns "false"
//! \~russian
bool PIMutex::tryLock() {
bool ret =
#if defined(WINDOWS)

View File

@@ -34,25 +34,25 @@ class PIP_EXPORT PIMutex
public:
NO_COPY_CLASS(PIMutex)
//! Constructs unlocked mutex
//! \~english Constructs unlocked mutex
//! \~russian Создает незаблокированный мьютекс
explicit PIMutex();
//! Destroy mutex
//! \~english Destroy mutex
//! \~russian Деструктор мьютекса
~PIMutex();
//! \brief Lock mutex
//! \details If mutex is unlocked it set to locked state and returns immediate.
//! If mutex is already locked function blocks until mutex will be unlocked
//! \~english Lock mutex
//! \~russian Блокирует мьютекс
void lock();
//! \brief Unlock mutex
//! \details In any case this function returns immediate
void unlock() ;
//! \~english Unlock mutex
//! \~russian Разблокирует мьютекс
void unlock();
//! \brief Try to lock mutex
//! \details If mutex is unlocked it set to locked state and returns "true" immediate.
//! If mutex is already locked function returns immediate an returns "false"
//! \~english Try to lock mutex
//! \~russian Пробует заблокировать мьютекс
bool tryLock();
void * handle();
@@ -66,22 +66,24 @@ private:
};
//! \brief PIMutexLocker
//! \details Same as std::lock_guard<std::mutex>.
//! When a PIMutexLocker object is created, it attempts to lock the mutex it is given, if "condition" true.
//! When control leaves the scope in which the PIMutexLocker object was created,
//! the PIMutexLocker is destructed and the mutex is released, if "condition" true.
//! If "condition" false this class do nothing.
//! The PIMutexLocker class is non-copyable.
class PIP_EXPORT PIMutexLocker
{
public:
NO_COPY_CLASS(PIMutexLocker)
//! \~english Constructs and lock "m" if "condition" is \c true
//! \~russian
PIMutexLocker(PIMutex & m, bool condition = true): mutex(m), cond(condition) {if (cond) mutex.lock();}
//! \~english Unlock "m" if "condition" was \c true
//! \~russian
~PIMutexLocker() {if (cond) mutex.unlock();}
private:
PIMutex & mutex;
bool cond;
};
#endif // PIMUTEX_H

View File

@@ -17,14 +17,49 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \class PISpinlock
* \brief Spinlock
* \details
* \section PISpinlock_sec0 Synopsis
* %PISpinlock provides synchronization blocks between several threads.
* PISpinlock functionality similar to PIMutex, but working on atomic
* type and \a lock() method wait with 100% CPU load.
* \note
* Use this type instead of PIMutex when less waiting time is more
* important than CPU load!
* */
//! \addtogroup Thread
//! \{
//! \class PISpinlock pispinlock.h
//!
//! \~\brief
//! \~english Fast and full-load lock
//! \~russian Быстрая блокировка с полной нагрузкой
//!
//! \~\details
//! \~english
//! %PISpinlock provides synchronization blocks between several threads.
//! PISpinlock functionality similar to PIMutex, but working on atomic
//! type and \a lock() method wait with 100% CPU load.
//!
//! \~russian
//!
//! \~\note
//! \~english
//! Use this type instead of PIMutex when less waiting time is more
//! important than CPU load!
//!
//! \~russian
//!
//! \}
//! \addtogroup Thread
//! \{
//! \class PISpinlockLocker pispinlock.h
//!
//! \~\brief
//! \~english %PISpinlock autolocker
//! \~russian
//!
//!
//! \~\details
//! \~english
//! When a PISpinlockLocker object is created, it attempts to lock the spinlock it is given, if "condition" true.
//! When control leaves the scope in which the PISpinlockLocker object was created,
//! the PISpinlockLocker is destructed and the spinlock is released, if "condition" true.
//! If "condition" false this class do nothing.
//! The PISpinlockLocker class is non-copyable.
//!
//! \~russian
//!
//! \}

View File

@@ -35,20 +35,30 @@ class PIP_EXPORT PISpinlock
public:
NO_COPY_CLASS(PISpinlock)
//! Constructs unlocked spinlock
//! \~english Constructs unlocked spinlock
//! \~russian
explicit PISpinlock() {flag.clear();}
//! Destroy spinlock
//! \~english Destroy spinlock
//! \~russian
~PISpinlock() {}
//! \brief Lock spinlock
//! \details If spinlock is unlocked it set to locked state and returns immediate.
//! \~english Lock spinlock
//! \~russian
//! \~\details
//! \~english
//! If spinlock is unlocked it set to locked state and returns immediate.
//! If spinlock is already locked function blocks until spinlock will be unlocked
//! \~russian
void lock() {while (flag.test_and_set(std::memory_order_acquire));}
//! \brief Unlock spinlock
//! \details In any case this function returns immediate
//! \~english Unlock spinlock
//! \~russian
//! \~\details
//! \~english
//! In any case this function returns immediate
//! \~russian
void unlock() {flag.clear(std::memory_order_release);}
private:
@@ -57,22 +67,24 @@ private:
};
//! \brief PISpinlockLocker
//! \details
//! When a PISpinlockLocker object is created, it attempts to lock the spinlock it is given, if "condition" true.
//! When control leaves the scope in which the PISpinlockLocker object was created,
//! the PISpinlockLocker is destructed and the spinlock is released, if "condition" true.
//! If "condition" false this class do nothing.
//! The PISpinlockLocker class is non-copyable.
class PIP_EXPORT PISpinlockLocker
{
public:
NO_COPY_CLASS(PISpinlockLocker)
//! \~english Constructs and lock "s" if "condition" is \c true
//! \~russian
PISpinlockLocker(PISpinlock & s, bool condition = true): spinlock(s), cond(condition) {if (cond) spinlock.lock();}
//! \~english Unlock "s" if "condition" was \c true
//! \~russian
~PISpinlockLocker() {if (cond) spinlock.unlock();}
private:
PISpinlock & spinlock;
bool cond;
};
#endif // PISPINLOCK_H

View File

@@ -54,54 +54,85 @@ __THREAD_FUNC_RET__ thread_function_once(void * t) {((PIThread*)t)->__thread_fun
# define UNREGISTER_THREAD(t)
#endif
/*! \class PIThread
* \brief Thread class
* \details This class allow you exec your code in separate thread.
*
* \section PIThread_sec0 Synopsis
* Multithreading allow you to write program which will be executed
* in several threads simultaneously. This trend allow you to use all
* cores of modern processors, but there are many dangers.
*
* This class provide virtual functions \a begin(), \a run() and \a end(),
* which describes start, execution and finish work of some process.
* These functions executes in \b separate thread. When you execute
* \a start(), %PIThread create separate system thread and sequentially
* executes function \a begin(), \a run() and \a end(). You can
* reimplement each function and write your own code to execute.
* Scheme of functions executing:
\code{.cpp}
begin();
event started();
while (isRunning()) {
run();
ThreadFunc();
piMSleep(timer_delay);
}
event stopped();
end();
\endcode
* Unlike from directly using "pthread" or some similar you doesn`t need
* to write your own main thread cycle and sleep at every cycle end.
* %PIThread make it for you, and your job is to set sleep value from
* contructor or when starting thread, and reimplement \a begin(), \a run()
* and \a end() functions.
*
* \section PIThread_sec1 Using without subclassing
* You can use %PIThread without subclassing by using "ThreadFunc" pointer
* that can be set from constructor or by overloaded function \a start(ThreadFunc func, int timer_delay).
* If "func" if not null this function will be executed as \a run(). ThreadFunc is any static
* function with format void func(void * data). "Data" is custom data set from constructor or
* with function \a setData(). \n Also you can connect to event \a started(), but
* in this case you should to white your thread main cycle, because this event raised only one time.
*
* \section PIThread_sec2 Locking
* %PIThread has inrternal mutex that can be locked and unlocked every \a run() if you set this flag
* with function \a needLockRun(bool). Also you can access to this mutex by functions \a lock(), \a unlock()
* and \a mutex(). Using this functions together with needLockRun(true) can guarantee one-thread access to
* some data.
*
*/
//! \addtogroup Thread
//! \{
//! \class PIThread pithread.h
//! \~\brief
//! \~english Thread class
//! \~russian Класс потока
//!
//! \~\details
//! \~english
//! This class allow you exec your code in separate thread.
//!
//! \~russian
//! Этот класс позволяет выполнять код из параллельного потока.
//!
//!
//! \~english \section PIThread_sec0 Synopsis
//! \~russian \section PIThread_sec0 Краткий обзор
//! \~english
//! Multithreading allow you to write program which will be executed
//! in several threads simultaneously. This trend allow you to use all
//! cores of modern processors, but there are many dangers.
//!
//! This class provide virtual functions \a begin(), \a run() and \a end(),
//! which describes start, execution and finish work of some process.
//! These functions executes in \b separate thread. When you execute
//! \a start(), %PIThread create separate system thread and sequentially
//! executes function \a begin(), \a run() and \a end(). You can
//! reimplement each function and write your own code to execute.
//! Scheme of functions executing:
//!
//! \~russian
//!
//! \~\code{.cpp}
//! begin();
//! event started();
//! while (isRunning()) {
//! run();
//! ThreadFunc();
//! piMSleep(timer_delay);
//! }
//! event stopped();
//! end();
//! \endcode
//!
//! \~english
//! Unlike from directly using "pthread" or some similar you doesn`t need
//! to write your own main thread cycle and sleep at every cycle end.
//! %PIThread make it for you, and your job is to set sleep value from
//! contructor or when starting thread, and reimplement \a begin(), \a run()
//! and \a end() functions.
//!
//! \~russian
//!
//!
//! \~english \section PIThread_sec1 Using without subclassing
//! \~russian \section PIThread_sec1 Использование без наследования
//! \~english
//! You can use %PIThread without subclassing by using "ThreadFunc" pointer
//! that can be set from constructor or by overloaded function \a start(ThreadFunc func, int timer_delay).
//! If "func" if not null this function will be executed as \a run(). ThreadFunc is any static
//! function with format void func(void * data). "Data" is custom data set from constructor or
//! with function \a setData(). \n Also you can connect to event \a started(), but
//! in this case you should to white your thread main cycle, because this event raised only one time.
//!
//! \~russian
//!
//!
//! \~english \section PIThread_sec2 Locking
//! \~russian \section PIThread_sec2 Блокировки
//! \~english
//! %PIThread has inrternal mutex that can be locked and unlocked every \a run() if you set this flag
//! with function \a needLockRun(bool). Also you can access to this mutex by functions \a lock(), \a unlock()
//! and \a mutex(). Using this functions together with needLockRun(true) can guarantee one-thread access to
//! some data.
//!
//! \~russian
//!
//! \}
//!
#ifndef MICRO_PIP

View File

@@ -65,6 +65,7 @@ static __PIThreadCollection_Initializer__ __PIThreadCollection_initializer__;
typedef std::function<void(void *)> ThreadFunc;
class PIP_EXPORT PIThread: public PIObject
{
PIOBJECT_SUBCLASS(PIThread, PIObject)
@@ -74,24 +75,28 @@ class PIP_EXPORT PIThread: public PIObject
public:
NO_COPY_CLASS(PIThread)
//! Contructs thread with custom data "data", external function "func" and main loop delay "loop_delay".
//! \~english Contructs thread with custom data "data", external function "func" and main loop delay "loop_delay"
//! \~russian Создает поток с данными "data", функцией "func" и задержкой цикла "loop_delay"
PIThread(void * data, ThreadFunc func, bool startNow = false, int loop_delay = -1);
//! Contructs thread with external function "func" and main loop delay "loop_delay".
//! \~english Contructs thread with external function "func" and main loop delay "loop_delay"
//! \~russian Создает поток с функцией "func" и задержкой цикла "loop_delay"
PIThread(std::function<void()> func, bool startNow = false, int loop_delay = -1);
//! Contructs thread with main loop delay "loop_delay".
//! \~english Contructs thread with main loop delay "loop_delay"
//! \~russian Создает поток с задержкой цикла "loop_delay"
PIThread(bool startNow = false, int loop_delay = -1);
virtual ~PIThread();
//! Priority of thread
//! \~english Priority of thread
//! \~russian Приоритет потока
enum Priority {
piLowerst /** Lowest */,
piLow /** Low */,
piNormal /** Normal, this is default priority of threads and timers */,
piHigh /** High */,
piHighest /** Highest */
piLowerst /** \~english Lowest \~russian Низший */ ,
piLow /** \~english Low \~russian Низкий */ ,
piNormal /** \~english Normal, this is default priority of threads and timers \~russian Нормальный, это приоритет по умолчанию для потоков и таймеров */ ,
piHigh /** \~english High \~russian Высокий */ ,
piHighest /** \~english Highest \~russian Высший */
};
EVENT_HANDLER0(bool, start) {return start(-1);}
@@ -106,27 +111,36 @@ public:
EVENT_HANDLER1(void, stop, bool, wait);
EVENT_HANDLER0(void, terminate);
//! \brief Set common data passed to external function
//! \~english Set common data passed to external function
//! \~russian Устанавливает данные, передаваемые в функцию потока
void setData(void * d) {data_ = d;}
//! \brief Set external function that will be executed after every \a run()
//! \~english Set external function that will be executed after every \a run()
//! \~russian Устанавливает функцию потока, вызываемую после каждого \a run()
void setSlot(ThreadFunc func) {ret_func = func;}
//! \brief Set external function that will be executed after every \a run()
//! \~english Set external function that will be executed after every \a run()
//! \~russian Устанавливает функцию потока, вызываемую после каждого \a run()
void setSlot(std::function<void()> func) {ret_func = [func](void*){func();};}
//! \brief Set priority of thread
//! \~english Set thread priority
//! \~russian Устанавливает приоритет потока
void setPriority(PIThread::Priority prior);
//! \brief Returns common data passed to external function
//! \~english Returns common data passed to external function
//! \~russian Возвращает данные, передаваемые в функцию потока
void * data() const {return data_;}
//! \brief Return priority of thread
//! \~english Return thread priority
//! \~russian Возвращает приоритет потока
PIThread::Priority priority() const {return priority_;}
//! \brief Return \c true if thread is running
//! \~english Return if thread is running
//! \~russian Возвращает исполняется ли поток
bool isRunning() const {return running_;}
//! \~english Return if thread is stopping
//! \~russian Возвращает останавливается ли поток
bool isStopping() const {return running_ && terminating;}
EVENT_HANDLER0(bool, waitForStart) {return waitForStart(-1);}
@@ -134,19 +148,19 @@ public:
EVENT_HANDLER0(bool, waitForFinish) {return waitForFinish(-1);}
EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs);
//! \brief Set necessity of lock every \a run with internal mutex
//! \~english Set necessity of lock every \a run() with internal mutex
//! \~russian Устанавливает необходимость блокировки внутреннего мьютекса каждый \a run()
void needLockRun(bool need) {lockRun = need;}
//! \brief Lock internal mutex
EVENT_HANDLER0(void, lock) const {thread_mutex.lock();}
//! \brief Unlock internal mutex
EVENT_HANDLER0(void, unlock) const {thread_mutex.unlock();}
//! \brief Returns internal mutex
//! \~english Returns internal mutex
//! \~russian Возвращает внутренний мьютекс
PIMutex & mutex() const {return thread_mutex;}
//! \brief Returns thread ID
//! \~english Returns thread ID
//! \~russian Возвращает ID потока
llong tid() const {return tid_;}
void __thread_func__();
@@ -155,93 +169,129 @@ public:
EVENT(started)
EVENT(stopped)
//! \brief Start event handler with name \"handler\" of object \"object\"
//! in separate thread with name \"name\"
//! \~english
//! Start event handler with name "handler" of object "object"
//! in separate thread with name "name"
//! and automatically delete it on function finish
//!
//! \~russian
static void runOnce(PIObject * object, const char * handler, const PIString & name = PIString());
//! \brief Start function \"func\" in separate thread with name \"name\"
//! \~english
//! Start function "func" in separate thread with name "name"
//! and automatically delete it on function finish
//!
//! \~russian
static void runOnce(std::function<void()> func, const PIString & name = PIString());
//! \handlers
//! \{
/** \fn bool start(int timer_delay = -1)
* \brief Start thread
* \details Start execution of \a run() in internal loop with
* "timer_delay" delay in milliseconds. If "timer_delay" <= 0
* there is no delay in loop. Thread also exec external function
* set by \a setSlot() if it`s not null
*
* \return \c false if thread already started or can`t start thread */
//! \fn bool start(int timer_delay = -1)
//! \~english Start thread
//! \~russian Запускает поток
//! \~\details
//! \~english
//! Start execution of \a run() in internal loop with
//! "timer_delay" delay in milliseconds. If "timer_delay" <= 0
//! there is no delay in loop. Thread also exec external function
//! set by \a setSlot() if it`s not null
//! \return \c false if thread already started or can`t start thread
//! \~russian
/** \fn bool startOnce()
* \brief Start thread without internal loop
* \details Start execution of \a run() once. Thread also exec
* external function set by \a setSlot() if it`s not null
*
* \return \c false if thread already started or can`t start thread */
//! \fn bool startOnce()
//! \~english Start thread without internal loop
//! \~russian Запускает поток без внутреннего цикла
//! \~\details
//! \~english
//! Start execution of \a run() once. Thread also exec
//! external function set by \a setSlot() if it`s not null
//! \return \c false if thread already started or can`t start thread
//! \~russian
/** \fn bool startOnce(ThreadFunc func)
* \brief Start thread without internal loop
* \details Overloaded function. Set external function "func" before start
*
* \return \c false if thread already started or can`t start thread */
//! \fn bool startOnce(ThreadFunc func)
//! \~english Start thread without internal loop
//! \~russian Запускает поток без внутреннего цикла
//! \~\details
//! \~english
//! Overloaded function. Set external function "func" before start
//! \return \c false if thread already started or can`t start thread
//! \~russian
/** \fn void stop(bool wait = false)
* \brief Stop thread
* \details Stop execution of thread and wait for it finish
* if "wait" is \c true. This function can block for infinite
* time if "wait" is \c true and any of thread function is
* busy forever */
//! \fn void stop(bool wait = false)
//! \~english Stop thread
//! \~russian Останавливает поток
//! \~\details
//! \~english
//! Stop execution of thread and wait for it finish
//! if "wait" is \c true. This function can block for infinite
//! time if "wait" is \c true and any of thread function is
//! busy forever
//! \~russian
/** \fn void terminate()
* \brief Strongly stop thread
* \details Stop execution of thread immediately */
//! \fn void terminate()
//! \~english Strongly stop thread
//! \~russian Жестко останавливает поток
//! \~\details
//! \~english
//! Stop execution of thread immediately
//! \~russian
/** \fn bool waitForStart(int timeout_msecs = -1)
* \brief Wait for thread start
* \details This function block until thread start for "timeout_msecs"
* or forever if "timeout_msecs" < 0
*
* \return \c false if timeout is exceeded */
//! \fn bool waitForStart(int timeout_msecs = -1)
//! \~english Wait for thread start
//! \~russian Ожидает старта потока
//! \~\details
//! \~english
//! This function block until thread start for "timeout_msecs"
//! or forever if "timeout_msecs" < 0
//! \return \c false if timeout is exceeded
//! \~russian
/** \fn bool waitForFinish(int timeout_msecs = -1)
* \brief Wait for thread finish
* \details This function block until thread finish for "timeout_msecs"
* or forever if "timeout_msecs" < 0
*
* \return \c false if timeout is exceeded */
//! \fn bool waitForFinish(int timeout_msecs = -1)
//! \~english Wait for thread finish
//! \~russian Ожидает завершения потока
//! \~\details
//! \~english
//! This function block until thread finish for "timeout_msecs"
//! or forever if "timeout_msecs" < 0
//! \return \c false if timeout is exceeded
//! \~russian
//! \fn void lock()
//! \brief Lock internal mutex
//! \~english Lock internal mutex
//! \~russian Блокирует внутренний мьютекс
//! \fn void unlock()
//! \brief Unlock internal mutex
//! \~english Unlock internal mutex
//! \~russian Разблокирует внутренний мьютекс
//! \}
//! \events
//! \{
//! \fn void started()
//! \brief Raise on thread start
//! \~english Raise on thread start
//! \~russian Вызывается при старте потока
//! \fn void stopped()
//! \brief Raise on thread stop
//! \~english Raise on thread stop
//! \~russian Вызывается при завершении потока
//! \}
protected:
static int priority2System(PIThread::Priority p);
//! Function executed once at the start of thread.
//! \~english Function executed once at the start of thread
//! \~russian Метод выполняется один раз при старте потока
virtual void begin() {;}
//! Function executed at every "timer_delay" msecs until thread was stopped.
//! \~english Function executed at every "timer_delay" msecs until thread was stopped
//! \~russian Метод выполняется каждые "timer_delay" миллисекунд
virtual void run() {;}
//! Function executed once at the end of thread.
//! \~english Function executed once at the end of thread
//! \~russian Метод выполняется один раз при остановке потока
virtual void end() {;}
std::atomic_bool terminating, running_, lockRun;

View File

@@ -19,10 +19,50 @@
#include "pithreadnotifier.h"
//! \addtogroup Thread
//! \{
//! \class PIThreadNotifier pithreadnotifier.h
//!
//! \~\brief
//! \~english Class for simple notify and wait in different threads
//! \~russian Класс для простого уведомления и ожидания в различных потоках
//!
//! \~\details
//! \~english
//!
//! \~russian
//!
//!
//! \~english \section PIThreadNotifier_sec0 Synopsis
//! \~russian \section PIThreadNotifier_sec0 Краткий обзор
//! \~english
//!
//! \~russian
//!
//!
//! \~english \section PIThreadNotifier_sec1 Usage
//! \~russian \section PIThreadNotifier_sec1 Использование
//! \~english
//!
//! \~russian
//!
//!
//! \}
PIThreadNotifier::PIThreadNotifier() : cnt(0) {}
//! \~\details
//! \~english
//! If \a notifyOnce() has been called before, then returns immediately.
//! If \a notifyOnce() has been called "n" times, then returns immediately "n" times,
//! but only if wait in one thread.
//! If many threads waiting, then if \a notifyOnce() has been called "n" times,
//! all threads total returns "n" times in random sequence.
//!
//! \~russian
//!
void PIThreadNotifier::wait() {
m.lock();
while (cnt == 0) v.wait(m);
@@ -31,6 +71,12 @@ void PIThreadNotifier::wait() {
}
//! \~\details
//! \~english
//! If many threads waiting, then notify randomly one.
//! If call this "n" times, then notify any waiting threads totally "n" times.
//!
//! \~russian
void PIThreadNotifier::notifyOnce() {
m.lock();
cnt++;

View File

@@ -33,17 +33,12 @@ class PIP_EXPORT PIThreadNotifier {
public:
PIThreadNotifier();
//! Start waiting, return if other thread call \a notifyOnce().
//! If \a notifyOnce() has been called before, then returns immediately.
//! If notifyOnce() has been called "n" times, then returns immediately "n" times,
//! but only if wait in one thread.
//! If many threads waiting, then If notifyOnce() has been called "n" times,
//! All threads total returns "n" times in random sequence.
//! \~english Start waiting, return if other thread call \a notifyOnce()
//! \~russian Начать ожидание, продолжает когда другой поток вызовет \a notifyOnce()
void wait();
//! Notify one waiting thread, wich waiting on \a wait() function.
//! If many threads waiting, then notify randomly one.
//! If call this "n" times, then notify any waiting threads totally "n" times.
//! \~english Notify one waiting thread, which waiting on \a wait() function
//! \~russian Уведомить один из ожидающих потоков, которые висят на методе \a wait()
void notifyOnce();
private:

View File

@@ -22,51 +22,82 @@
#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<int> 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<int> 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.
*
*/
//! \addtogroup Thread
//! \{
//! \class PIThreadPoolLoop pithreadpoolloop.h
//! \~english Thread pool loop
//! \~russian Пул потоков
//!
//! \~\details
//! \~english
//! This class allow you parallelize loop.
//!
//! \~russian
//! Этот класс позволяет распараллелить цикл
//!
//!
//! \~english \section PIThreadPoolLoop_sec0 Usage
//! \~russian \section PIThreadPoolLoop_sec0 Использование
//! \~english
//! This class designed to parallel "for(;;)" statement in very simple way.
//! In constructor several threads created, then by \a setFunction() method
//! you should pass body of your loop, and then call \a start() or \a exec().
//! Every thread take loop counter and execute your function until all
//! counter range is passed.
//!
//! Example:
//! \~russian
//! Этот класс предназначен для распараллеливания цикла "for(;;)" максимально простым способом.
//! В конструкторе создается несколько потоков, затем методом \a setFunction()
//! устанавливается функция, представляющая собой тело цикла. Затем вызовом
//! \a start() или \a exec() цикл исполняется параллельно. Каждый поток получает
//! значение переменной цикла и вызывает функцию-тело до тех пор, пока
//! весь диапазон не будет исполнен.
//!
//! Пример:
//!
//! \~\code{.cpp}
//! PIVector<int> 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
//!
//! \~english Equivalent to:
//! \~russian Эквивалентно:
//! \~\code{.cpp}
//! PIVector<int> 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
//!
//!
//! \~english \section PIThreadPoolLoop_sec1 Important
//! \~russian \section PIThreadPoolLoop_sec1 Важно
//! \~english
//! 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.
//!
//! \~russian
//! В силу многопоточности очень важно защитить выходные данные тела цикла с помощью блокировок (мьютекса).
//! Также стоит помнить, что последовательность выполнения неопределена, и не стоит использовать глобальных
//! переменных в теле цикла. Используйте локальные переменные и захват в лямбде.
//!
//! \}
PIThreadPoolLoop::PIThreadPoolLoop(int thread_cnt) {

View File

@@ -33,30 +33,50 @@ class PIThread;
class PIP_EXPORT PIThreadPoolLoop {
public:
//! \~english
//! Contructs thread pool with threads count "thread_cnt".
//! If "thread_cnt" = -1 then system processors count used
//! \~russian
//! Создает пул из "thread_cnt" потоков. Если "thread_cnt" = -1
//! то используется количество процессоров системы
PIThreadPoolLoop(int thread_cnt = -1);
virtual ~PIThreadPoolLoop();
//! Set threads function to "f" with format [](int){...}
//! \~english Set threads function to "f" with format [ ](int){ ... }
//! \~russian Устанавливает функцию потоков на "f" в формате [ ](int){ ... }
void setFunction(std::function<void(int)> f);
//! Wait for all threads stop
//! \~english Wait for all threads stop
//! \~russian Ожидает завершения всех потоков
void wait();
//! \~english
//! Start functions execution with integer argument range
//! from "index_start" to "index_start + index_count - 1"
//! \~russian
//! Начинает исполнение потоков с аргументами по диапазону
//! от "index_start" до "index_start + index_count - 1"
void start(int index_start, int index_count);
//! \~english
//! Start functions execution with integer argument range
//! from "index_start" to "index_start + index_count - 1"
//! and wait for finish
//! \~russian
//! Начинает исполнение потоков с аргументами по диапазону
//! от "index_start" до "index_start + index_count - 1"
//! и ожидает завершения
void exec(int index_start, int index_count);
//! \~english
//! Start functions "f" execution with integer argument range
//! from "index_start" to "index_start + index_count - 1"
//! and wait for finish
//! \~russian
//! Начинает исполнение потоками функции "f" с аргументами по диапазону
//! от "index_start" до "index_start + index_count - 1"
//! и ожидает завершения
void exec(int index_start, int index_count, std::function<void(int)> f);
private:

View File

@@ -24,31 +24,94 @@
#endif
/*! \class PITimer
* \brief Timer
*
* \section PITimer_sec0 Synopsis
* This class implements timer function. PIP timers supports 3 way to tick notify,
* frequency delimiters and time measurements.
* \section PITimer_sec1 Notify variants
* Notify variants:
* * "slot" - static function with format void func(void * data, int delimiter);
* * event - \a tickEvent();
* * virtual function - \a tick().
*
* All these variants are equivalent, use most applicable.
* \section PITimer_sec2 Frequency delimiters
* Frequency delimiter is an integer number and "slot" function. If "slot" function is null
* timer main "slot" will be used. Each delimiter numbers tick timer will be execute
* delimiters or timer main "slot" function with \b delimiter value = delimiter number.
* Example: \snippet pitimer.cpp delimiter
* \section PITimer_sec3 Time measurements
* PITimer can be used as time measurer. Function \a reset() set time mark to current
* system time, then functions double elapsed_*() returns time elapsed from this mark.
* These functions can returns nano-, micro-, milli- and seconds with suffixes "n", "u", "m"
* and "s"
* Example: \snippet pitimer.cpp elapsed
*/
//! \addtogroup Thread
//! \{
//! \class PITimer pitimer.h
//!
//! \~\brief
//! \~english Timer
//! \~russian Таймер
//!
//! \~\details
//!
//! \~english \section PITimer_sec0 Synopsis
//! \~russian \section PITimer_sec0 Краткий обзор
//! \~english
//! This class implements timer function. PIP timers supports 3 way to tick notify,
//! deferred start and frequency delimiters.
//!
//! \~russian
//! Этот класс реализует таймер. Таймер PIP поддерживает 3 варианта уведомления,
//! отложенный старт и делители частоты.
//!
//!
//! \~english \section PITimer_sec1 Notify variants
//! \~russian \section PITimer_sec1 Варианты уведомления
//! \~english
//! Notify variants:
//! * "slot" - static function with format void func(void * data, int delimiter) or lambda-function;
//! * event - \a tickEvent();
//! * virtual function - \a tick().
//!
//! Lambda should be [ ]( ){ } or [ ](void*){ } format.
//!
//! All these variants are equivalent, use most applicable.
//! \~russian
//! Варианты уведомления:
//! * "slot" - статический метод в формате void func(void * data, int delimiter) или лямбда-функция;
//! * event - \a tickEvent();
//! * виртуальный метод - \a tick().
//!
//! Лямбда-функция должна быть в формате [ ]( ){ } или [ ](void*){ }.
//!
//! Все варианты аналогичны друг другу, используйте самый удобный.
//!
//!
//! \~english \section PITimer_sec2 Frequency delimiters
//! \~russian \section PITimer_sec2 Делители частоты
//! \~english
//! Frequency delimiter is an integer number and "slot" function. If "slot" function is null
//! timer main "slot" will be used. Each delimiter numbers tick timer will be execute
//! delimiters or timer main "slot" function with \b delimiter value = delimiter number.
//!
//! Example:
//!
//! \~russian
//! Делитель частоты это целое число и необязательный метод "slot". Если метод не указан,
//! то будет использован основной "slot". Каждые \b delimiter тиков будет дополнительно вызван
//! "slot" делителя либо основной "slot" с аргументом \b delimiter равным значению делителя.
//!
//! Пример:
//!
//! \~\code
//! void tfunc(void * , int delim) {
//! piCout << "tick with delimiter" << delim;
//! };
//! void tfunc4(void * , int delim) {
//! piCout << "tick4 with delimiter" << delim;
//! };
//! int main() {
//! PITimer timer(tfunc);
//! timer.addDelimiter(2);
//! timer.addDelimiter(4, tfunc4);
//! timer.start(50);
//! piMSleep(200);
//! timer.stop();
//! timer.waitForFinish();
//! return 0;
//! };
//! /* Result:
//! tick with delimiter 1
//! tick with delimiter 1
//! tick with delimiter 2
//! tick with delimiter 1
//! tick with delimiter 1
//! tick with delimiter 2
//! tick4 with delimiter 4
//! */
//! \endcode
//!
//! \}
_PITimerBase::_PITimerBase() {
@@ -603,23 +666,43 @@ bool PITimer::start(int interval_ms_i) {
}
//! \~\details
//! \~english
//! Timer wait "delay_msecs" milliseconds and then normally starts with \a interval() loop delay
//! \~russian
//! Таймер ожидает "delay_msecs" миллисекунд, а затем стартует с интервалом \a interval()
void PITimer::startDeferred(double delay_ms) {
init();
imp->startDeferred(delay_ms);
}
//! \~\details
//! \~english
//! Timer wait "delay_msecs" milliseconds and then normally starts with "interval_msecs" loop delay
//! \~russian
//! Таймер ожидает "delay_msecs" миллисекунд, а затем стартует с интервалом "interval_msecs"
void PITimer::startDeferred(double interval_ms, double delay_ms) {
init();
imp->startDeferred(interval_ms, delay_ms);
}
//! \~\details
//! \~english
//! Timer wait until "start_datetime" and then normally starts with \a interval() loop delay
//! \~russian
//! Таймер ожидает наступления "start_datetime", а затем стартует с интервалом \a interval()
void PITimer::startDeferred(PIDateTime start_datetime) {
startDeferred(imp->interval_, start_datetime);
}
//! \~\details
//! \~english
//! Timer wait until "start_datetime" and then normally starts with "interval_msecs" loop delay
//! \~russian
//! Таймер ожидает наступления "start_datetime", а затем стартует с интервалом "interval_msecs"
void PITimer::startDeferred(double interval_ms, PIDateTime start_datetime) {
init();
imp->startDeferred(interval_ms, start_datetime);

View File

@@ -42,7 +42,6 @@ public:
double interval() const {return interval_;}
void setInterval(double i);
//! \brief Return \c true if thread is running
bool isRunning() const {return running_;}
bool isStopped() const {return !running_;}
@@ -79,45 +78,64 @@ class PIP_EXPORT PITimer: public PIObject {
public:
NO_COPY_CLASS(PITimer)
//! \brief Constructs timer with PITimer::Thread implementation
//! \~english Constructs timer with PITimer::Thread implementation
//! \~russian Создает таймер с реализацией PITimer::Thread
explicit PITimer();
//! \brief Timer implementations
//! \~english Timer implementations
//! \~russian Реализация таймера
enum TimerImplementation {
Thread /*! Timer works in his own thread. Intervals are measured by the system time */ = 0x01,
ThreadRT /*! Using POSIX timer with SIGEV_THREAD notification. \attention Doesn`t support on Windows and Mac OS! */ = 0x02,
Pool /*! Using single TimerPool for all timers with this implementation. TimerPool works as Thread implementation and
* sequentially executes all timers. \attention Use this implementation with care! */ = 0x04
Thread /*!
\~english Timer works in his own thread. Intervals are measured by the system time
\~russian Таймер работает в собственном потоке. Интервалы измеряются с помощью системного времени
*/ = 0x01,
ThreadRT /*!
\~english Using POSIX timer with SIGEV_THREAD notification. \attention Doesn`t support on Windows and Mac OS!
\~russian Использовать таймер POSIX с SIGEV_THREAD уведомлением. \attention Не поддерживается на Windows и Mac OS!
*/ = 0x02,
Pool /*!
\~english Using single TimerPool for all timers with this implementation. TimerPool works as Thread implementation and
sequentially executes all timers. \attention Use this implementation with care!
\~russian Использовать единый TimerPool для всех таймеров с этой реализацией. TimerPool реализован через Thread и
последовательно исполняет все таймеры. \attention Осторожнее с этой реализацией!
*/ = 0x04
};
//! \brief Constructs timer with "ti" implementation
//! \~english Constructs timer with "ti" implementation
//! \~russian Создает таймер с реализацией "ti"
explicit PITimer(TimerImplementation ti);
//! \brief Constructs timer with "slot" slot void(void *,int), "data" data and "ti" implementation
//! \~english Constructs timer with "slot" slot void(void *,int), "data" data and "ti" implementation
//! \~russian Создает таймер со слотом "slot", данными "data" и реализацией "ti"
explicit PITimer(TimerEvent slot, void * data = 0, TimerImplementation ti = Thread);
//! \brief Constructs timer with "slot" slot void(), and "ti" implementation
//! \~english Constructs timer with "slot" slot void(), and "ti" implementation
//! \~russian Создает таймер со слотом "slot" и реализацией "ti"
explicit PITimer(std::function<void ()> slot, TimerImplementation ti = Thread);
//! \brief Constructs timer with "slot" slot void(void *), "data" data and "ti" implementation
//! \~english Constructs timer with "slot" slot void(void *), "data" data and "ti" implementation
//! \~russian Создает таймер со слотом "slot", данными "data" и реализацией "ti"
explicit PITimer(std::function<void (void *)> slot, void * data, TimerImplementation ti = Thread);
virtual ~PITimer();
//! \brief Returns timer implementation
//! \~english Returns timer implementation
//! \~russian Возвращает реализацию таймера
PITimer::TimerImplementation implementation() const {return imp_mode;}
//! \brief Returns timer loop delay in milliseconds
//! \~english Returns timer loop delay in milliseconds
//! \~russian Возвращает задержку цикла таймера в миллисекундах
double interval() const;
//! \brief Set timer loop delay in milliseconds
EVENT_HANDLER1(void, setInterval, double, ms);
//! \brief Returns if timer is started
//! \~english Returns if timer is started
//! \~russian Возвращает работает ли таймер
bool isRunning() const;
//! \brief Returns if timer is not started
//! \~english Returns if timer is not started
//! \~russian Возвращает остановлен ли таймер
bool isStopped() const;
EVENT_HANDLER0(bool, start);
@@ -126,24 +144,20 @@ public:
EVENT_HANDLER0(bool, restart);
/** \brief Start timer with \b interval() loop delay after \b delay_msecs delay.
* \details Timer wait \b delay_msecs milliseconds and then normally starts with
* \b interval() loop delay. */
//! \~english Start timer with \a interval() loop delay after "delay_msecs" delay
//! \~russian Запускает таймер с интервалом \a interval() после ожидания "delay_msecs"
void startDeferred(double delay_ms);
/** \brief Start timer with \b interval_msecs loop delay after \b delay_msecs delay.
* \details Timer wait \b delay_msecs milliseconds and then normally starts with
* \b interval_msecs loop delay. */
//! \~english Start timer with "interval_msecs" loop delay after "delay_msecs" delay
//! \~russian Запускает таймер с интервалом "interval_msecs" после ожидания "delay_msecs"
void startDeferred(double interval_ms, double delay_ms);
/** \brief Start timer with \b interval() loop delay after \b start_datetime date and time.
* \details Timer wait until \b start_datetime and then normally starts with
* \b interval() loop delay. */
//! \~english Start timer with \a interval() loop delay after "start_datetime" date and time
//! \~russian Запускает таймер с интервалом \a interval() после наступления "start_datetime"
void startDeferred(PIDateTime start_datetime);
/** \brief Start timer with \b interval_msecs loop delay after \b start_datetime date and time.
* \details Timer wait until \b start_datetime and then normally starts with
* \b interval_msecs loop delay. */
//! \~english Start timer with "interval_msecs" loop delay after "start_datetime" date and time
//! \~russian Запускает таймер с интервалом "interval_msecs" после наступления "start_datetime"
void startDeferred(double interval_ms, PIDateTime start_datetime);
EVENT_HANDLER0(bool, stop);
@@ -151,43 +165,52 @@ public:
bool waitForFinish() {return waitForFinish(-1);}
bool waitForFinish(int timeout_msecs);
//! \brief Set custom data
//! \~english Set custom data
//! \~russian Установить данные, передаваемые в метод таймера
void setData(void * data_) {data_t = data_;}
//! \brief Set timer tick function
//! \~english Returns common data passed to tick functions
//! \~russian Возвращает данные, передаваемые в метод таймера
void * data() const {return data_t;}
//! \~english Set timer tick function
//! \~russian Установить вызываемый метод
void setSlot(TimerEvent slot) {ret_func = slot;}
//! \brief Set timer tick function
//! \~english Set timer tick function
//! \~russian Установить вызываемый метод
void setSlot(std::function<void ()> slot) {ret_func = [slot](void *, int){slot();};}
//! \brief Set timer tick function
//! \~english Set timer tick function
//! \~russian Установить вызываемый метод
void setSlot(std::function<void (void *)> slot) {ret_func = [slot](void *d, int){slot(d);};}
//! \brief Returns common data passed to tick functions
void * data() const {return data_t;}
void needLockRun(bool need) {lockRun = need;}
EVENT_HANDLER0(void, lock) {mutex_.lock();}
EVENT_HANDLER0(void, unlock) {mutex_.unlock();}
//! \brief Returns if timer should exec \a maybeCallQueuedEvents() at every tick.
//! By default \b true
//! \~english Returns if timer should exec \a maybeCallQueuedEvents() at every tick. By default \b true
//! \~russian Возвращает должен ли таймер вызывать \a maybeCallQueuedEvents() каждый тик. По умолчанию \b true
bool isCallQueuedEvents() const {return callEvents;}
//! \brief If set timer exec \a maybeCallQueuedEvents() at every tick.
//! By default \b true
//! \~english Set timer exec \a maybeCallQueuedEvents() at every tick
//! \~russian Установает должен ли таймер вызывать \a maybeCallQueuedEvents() каждый тик
void setCallQueuedEvents(bool yes) {callEvents = yes;}
//! \brief Add frequency delimiter \b delim with optional delimiter slot \b slot.
//! \~english Add frequency delimiter "delim" with optional delimiter slot "slot"
//! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot"
void addDelimiter(int delim, TimerEvent slot = 0) {delims << Delimiter(slot, delim);}
//! \brief Add frequency delimiter \b delim with optional delimiter slot \b slot.
//! \~english Add frequency delimiter "delim" with optional delimiter slot "slot"
//! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot"
void addDelimiter(int delim, std::function<void ()> slot) {delims << Delimiter([slot](void *, int){slot();}, delim);}
//! \brief Add frequency delimiter \b delim with optional delimiter slot \b slot.
//! \~english Add frequency delimiter "delim" with optional delimiter slot "slot"
//! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot"
void addDelimiter(int delim, std::function<void (void *)> slot) {delims << Delimiter([slot](void *d, int){slot(d);}, delim);}
//! \brief Remove all frequency delimiters \b delim.
//! \~english Remove all frequency delimiters "delim"
//! \~russian Удаляет все делители частоты "delim"
void removeDelimiter(int delim) {for (int i = 0; i < delims.size_s(); ++i) if (delims[i].delim == delim) {delims.remove(i); i--;}}
EVENT_HANDLER0(void, clearDelimiters) {delims.clear();}
@@ -197,33 +220,58 @@ public:
//! \handlers
//! \{
/** \fn bool start()
* \brief Start timer with \a interval() loop delay
* \details Start execution of timer functions with frequency = 1 / msecs Hz. */
//! \fn void setInterval(double ms)
//! \~english Set timer loop delay in milliseconds
//! \~russian Установить интервал таймера "ms" миллисекунд
/** \fn bool start(double msecs)
* \brief Start timer with \b msecs loop delay
* \details Start execution of timer functions with frequency = 1. / msecs Hz.
* Instead of \a start(int msecs) function this variant allow start timer
* with frequencies more than 1 kHz */
//! \fn bool start()
//! \~english Start timer with \a interval() loop delay
//! \~russian Запустить таймер с интервалом \a interval()
//! \~\details
//! \~english
//! Start execution of timer functions with frequency = 1 / msecs Hz
//! \~russian
//! Запускает таймер с частотой = 1 / msecs Гц
//! \fn bool start(double msecs)
//! \~english Start timer with "msecs" loop delay
//! \~russian Запустить таймер с интервалом "msecs"
//! \~\details
//! \~english
//! Start execution of timer functions with frequency = 1. / msecs Hz.
//! Instead of \a start(int msecs) this function allow start timer
//! with frequencies more than 1 kHz
//! \~russian
//! Запускает таймер с частотой = 1 / msecs Гц. В отличии от
//! \a start(int msecs) этот метод позволяет запустить таймер с частотой
//! более 1 кГц
//! \fn bool restart()
//! \brief Stop and start timer with \a interval() loop delay
//! \~english Stop and start timer with \a interval() loop delay
//! \~russian Остановить и запустить таймер с интервалом \a interval()
//! \fn bool stop(bool wait = true)
//! \brief Stop timer and wait for it finish if "wait"
//! \~english Stop timer and wait for it finish if "wait"
//! \~russian Остановить таймер и если "wait" то дождаться остановки
//! \fn void clearDelimiters()
//! \brief Remove all frequency delimiters
//! \~english Remove all frequency delimiters
//! \~russian Удаляет все делители частоты
//! \}
//! \events
//! \{
/** \fn void tickEvent(void * data, int delimiter)
* \brief Raise on timer tick
* \details \b Data can be set with function \a setData(void * data) or from constructor.
* \b Delimiter is frequency delimiter, 1 for main loop. */
//! \fn void tickEvent(void * data, int delimiter)
//! \~english Raise on timer tick
//! \~russian Вызывается каждый тик таймера
//! \~\details
//! \~english
//! "data" can be set with function \a setData() or from constructor.
//! "delimiter" is frequency delimiter, 1 for main loop.
//! \~russian
//! "data" устанавливается методом \a setData() или в конструкторе.
//! "delimiter" - делитель частоты, 1 для основного цикла
//! \}
@@ -243,8 +291,7 @@ protected:
static void tickImpS(PITimer * t) {t->tickImp();}
void tickImp();
//! Virtual timer execution function, similar to "slot" or event \a void timeout(void * data, int delimiter).
//! By default is empty.
//! Timer execution function, similar to "slot" or event \a timeout(). By default does nothing
virtual void tick(void * data_, int delimiter) {}
void * data_t;