code format

This commit is contained in:
2022-12-14 14:13:52 +03:00
parent 430a41fefc
commit c2b8a8d6da
297 changed files with 27331 additions and 24162 deletions

View File

@@ -5,50 +5,53 @@
* \~russian Блокирующая очередь
*/
/*
PIP - Platform Independent Primitives
Stephan Fomenko
PIP - Platform Independent Primitives
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.
Stephan Fomenko
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.
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.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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 <http://www.gnu.org/licenses/>.
*/
#ifndef PIBLOCKINGQUEUE_H
#define PIBLOCKINGQUEUE_H
#include "pideque.h"
#include "piconditionvar.h"
#include "pideque.h"
/**
* \brief A Queue that supports operations that wait for the queue to become non-empty when retrieving an element, and
* wait for space to become available in the queue when storing an element.
*/
template <typename T>
template<typename T>
class PIBlockingQueue: private PIQueue<T> {
public:
/**
* \brief Constructor
*/
explicit inline PIBlockingQueue(size_t capacity = SIZE_MAX,
PIConditionVariable* cond_var_add = new PIConditionVariable(),
PIConditionVariable* cond_var_rem = new PIConditionVariable())
: cond_var_add(cond_var_add), cond_var_rem(cond_var_rem), max_size(capacity) { }
explicit inline PIBlockingQueue(size_t capacity = SIZE_MAX,
PIConditionVariable * cond_var_add = new PIConditionVariable(),
PIConditionVariable * cond_var_rem = new PIConditionVariable())
: cond_var_add(cond_var_add)
, cond_var_rem(cond_var_rem)
, max_size(capacity) {}
/**
* \brief Copy constructor. Initialize queue with copy of other queue elements. Not thread-safe for other queue.
*/
explicit inline PIBlockingQueue(const PIDeque<T>& other) : cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) {
explicit inline PIBlockingQueue(const PIDeque<T> & other)
: cond_var_add(new PIConditionVariable())
, cond_var_rem(new PIConditionVariable()) {
mutex.lock();
max_size = SIZE_MAX;
PIDeque<T>::append(other);
@@ -58,11 +61,11 @@ public:
/**
* \brief Thread-safe copy constructor. Initialize queue with copy of other queue elements.
*/
inline PIBlockingQueue(PIBlockingQueue<T> & other) : cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) {
inline PIBlockingQueue(PIBlockingQueue<T> & other): cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) {
other.mutex.lock();
mutex.lock();
max_size = other.max_size;
PIDeque<T>::append(static_cast<PIDeque<T>&>(other));
PIDeque<T>::append(static_cast<PIDeque<T> &>(other));
mutex.unlock();
other.mutex.unlock();
}
@@ -86,7 +89,7 @@ public:
return *this;
}
PIBlockingQueue<T> & enqueue(const T & v) {return put(v);}
PIBlockingQueue<T> & enqueue(const T & v) { return put(v); }
/**
* \brief Inserts the specified element at the end of this queue if it is possible to do so immediately without
@@ -102,7 +105,7 @@ public:
if (timeoutMs == 0)
isOk = PIDeque<T>::size() < max_size;
else
isOk = cond_var_rem->waitFor(mutex, timeoutMs, [&]() { return PIDeque<T>::size() < max_size; } );
isOk = cond_var_rem->waitFor(mutex, timeoutMs, [&]() { return PIDeque<T>::size() < max_size; });
if (isOk) PIDeque<T>::push_back(v);
mutex.unlock();
if (isOk) cond_var_add->notifyOne();
@@ -124,7 +127,7 @@ public:
return t;
}
T dequeue() {return take();}
T dequeue() { return take(); }
/**
* \brief Retrieves and removes the head of this queue, waiting up to the specified wait time if necessary for an
@@ -191,10 +194,11 @@ public:
/**
* \brief Removes all available elements from this queue and adds them to other given queue.
*/
size_t drainTo(PIDeque<T>& other, size_t maxCount = SIZE_MAX) {
size_t drainTo(PIDeque<T> & other, size_t maxCount = SIZE_MAX) {
mutex.lock();
size_t count = ((maxCount > PIDeque<T>::size()) ? PIDeque<T>::size() : maxCount);
for (size_t i = 0; i < count; ++i) other.push_back(PIDeque<T>::take_front());
for (size_t i = 0; i < count; ++i)
other.push_back(PIDeque<T>::take_front());
mutex.unlock();
return count;
}
@@ -202,13 +206,14 @@ public:
/**
* \brief Removes all available elements from this queue and adds them to other given queue.
*/
size_t drainTo(PIBlockingQueue<T>& other, size_t maxCount = SIZE_MAX) {
size_t drainTo(PIBlockingQueue<T> & other, size_t maxCount = SIZE_MAX) {
mutex.lock();
other.mutex.lock();
size_t count = maxCount > PIDeque<T>::size() ? PIDeque<T>::size() : maxCount;
size_t otherRemainingCapacity = other.max_size - static_cast<PIDeque<T> >(other).size();
size_t count = maxCount > PIDeque<T>::size() ? PIDeque<T>::size() : maxCount;
size_t otherRemainingCapacity = other.max_size - static_cast<PIDeque<T>>(other).size();
if (count > otherRemainingCapacity) count = otherRemainingCapacity;
for (size_t i = 0; i < count; ++i) other.push_back(PIDeque<T>::take_front());
for (size_t i = 0; i < count; ++i)
other.push_back(PIDeque<T>::take_front());
other.mutex.unlock();
mutex.unlock();
return count;
@@ -216,9 +221,8 @@ public:
private:
PIMutex mutex;
PIConditionVariable * cond_var_add, * cond_var_rem;
PIConditionVariable *cond_var_add, *cond_var_rem;
size_t max_size;
};

View File

@@ -1,20 +1,20 @@
/*
PIP - Platform Independent Primitives
PIP - Platform Independent Primitives
Stephan Fomenko
Stephan Fomenko
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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piplatform.h"
@@ -24,13 +24,13 @@
#endif
#include "piconditionvar.h"
#include "piincludes_p.h"
#include "pithread.h"
#include "pitime.h"
#include "piincludes_p.h"
#ifdef WINDOWS
# include <synchapi.h>
# include <windef.h>
# include <winbase.h>
# include <windef.h>
#endif
#ifdef FREERTOS
# include <event_groups.h>
@@ -76,19 +76,19 @@ PIConditionVariable::~PIConditionVariable() {
}
void PIConditionVariable::wait(PIMutex& lk) {
void PIConditionVariable::wait(PIMutex & lk) {
#if defined(WINDOWS)
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), INFINITE);
#elif defined(FREERTOS)
xEventGroupClearBits(PRIVATE->nativeHandle, 1);
xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, portMAX_DELAY);
#else
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t *)lk.handle());
#endif
}
void PIConditionVariable::wait(PIMutex& lk, const std::function<bool()>& condition) {
void PIConditionVariable::wait(PIMutex & lk, const std::function<bool()> & condition) {
bool isCondition;
while (true) {
isCondition = condition();
@@ -99,33 +99,33 @@ void PIConditionVariable::wait(PIMutex& lk, const std::function<bool()>& conditi
xEventGroupClearBits(PRIVATE->nativeHandle, 1);
xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, portMAX_DELAY);
#else
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t *)lk.handle());
#endif
}
}
bool PIConditionVariable::waitFor(PIMutex &lk, int timeoutMs) {
bool PIConditionVariable::waitFor(PIMutex & lk, int timeoutMs) {
bool isNotTimeout;
#if defined(WINDOWS)
isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs) != 0;
#elif defined(FREERTOS)
xEventGroupClearBits(PRIVATE->nativeHandle, 1);
EventBits_t uxBits;
uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, timeoutMs / portTICK_PERIOD_MS);
uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, timeoutMs / portTICK_PERIOD_MS);
isNotTimeout = (uxBits & 1) != 0;
#else
timespec expire_ts;
PISystemTime st = PISystemTime::current(true);
st.addMilliseconds(timeoutMs);
st.toTimespec(&expire_ts);
isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &expire_ts) == 0;
isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t *)lk.handle(), &expire_ts) == 0;
#endif
return isNotTimeout;
}
bool PIConditionVariable::waitFor(PIMutex& lk, int timeoutMs, const std::function<bool()> &condition) {
bool PIConditionVariable::waitFor(PIMutex & lk, int timeoutMs, const std::function<bool()> & condition) {
bool isCondition;
#if defined(WINDOWS) || defined(FREERTOS)
PITimeMeasurer measurer;
@@ -143,16 +143,15 @@ bool PIConditionVariable::waitFor(PIMutex& lk, int timeoutMs, const std::functio
if (isCondition) break;
bool isTimeout;
#if defined(WINDOWS)
isTimeout = SleepConditionVariableCS(
&PRIVATE->nativeHandle,
(PCRITICAL_SECTION)lk.handle(),
timeoutMs - (int)measurer.elapsed_m()) == 0;
isTimeout =
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs - (int)measurer.elapsed_m()) == 0;
#elif defined(FREERTOS)
EventBits_t uxBits;
uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, (timeoutMs - (int)measurer.elapsed_m()) / portTICK_PERIOD_MS);
isTimeout = (uxBits & 1) == 0;
EventBits_t uxBits;
uxBits =
xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, (timeoutMs - (int)measurer.elapsed_m()) / portTICK_PERIOD_MS);
isTimeout = (uxBits & 1) == 0;
#else
isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &expire_ts) != 0;
isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t *)lk.handle(), &expire_ts) != 0;
#endif
if (isTimeout) return false;
}
@@ -180,4 +179,3 @@ void PIConditionVariable::notifyAll() {
pthread_cond_broadcast(&PRIVATE->nativeHandle);
#endif
}

View File

@@ -5,22 +5,22 @@
* \~russian Conditional variable
*/
/*
PIP - Platform Independent Primitives
Stephan Fomenko
PIP - Platform Independent Primitives
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.
Stephan Fomenko
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.
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.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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 <http://www.gnu.org/licenses/>.
*/
#ifndef PICONDITIONVAR_H
@@ -82,7 +82,7 @@ public:
* @param condition A callable object or function that takes no arguments and returns a value that can be evaluated
* as a bool. This is called repeatedly until it evaluates to true.
*/
virtual void wait(PIMutex& lk, const std::function<bool()>& condition);
virtual void wait(PIMutex & lk, const std::function<bool()> & condition);
/**
* \brief see waitFor(PIMutex &, int, const std::function<bool()>&)
@@ -114,7 +114,7 @@ public:
* as a bool. This is called repeatedly until it evaluates to true.
* @return false if timeout reached or true if wakeup condition is true
*/
virtual bool waitFor(PIMutex& lk, int timeoutMs, const std::function<bool()>& condition);
virtual bool waitFor(PIMutex & lk, int timeoutMs, const std::function<bool()> & condition);
private:
PRIVATE_DECLARATION(PIP_EXPORT)

View File

@@ -5,45 +5,43 @@
* \~russian Базовый класс для создания грабберов
*/
/*
PIP - Platform Independent Primitives
Abstract class for create grabbers
Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
Abstract class for create grabbers
Andrey Bychkov work.a.b@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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIGRABBERBASE_H
#define PIGRABBERBASE_H
#include "pithread.h"
#include "pidiagnostics.h"
#include "pithread.h"
template<typename T = PIByteArray>
class PIGrabberBase: public PIThread
{
class PIGrabberBase: public PIThread {
PIOBJECT_SUBCLASS(PIGrabberBase, PIThread);
public:
PIGrabberBase() {
is_opened = false;
is_opened = false;
is_recording = false;
}
virtual ~PIGrabberBase() {
stopGrabber(false);
}
virtual bool isOpened() const {return is_opened;}
virtual bool isRecording() const {return is_recording;}
virtual ~PIGrabberBase() { stopGrabber(false); }
virtual bool isOpened() const { return is_opened; }
virtual bool isRecording() const { return is_recording; }
virtual void startRecord(const PIString & filename) {
if (!isOpened()) return;
if (isRecording()) return;
@@ -83,20 +81,21 @@ public:
}
T dequeue() {
T ret;
// piCoutObj << "start";
// piCoutObj << "start";
que_mutex.lock();
if (!que.isEmpty()) {
// piCoutObj << "dequeue";
// piCoutObj << "dequeue";
ret = que.dequeue();
}
// piCoutObj << "end";
// piCoutObj << "end";
que_mutex.unlock();
return ret;
}
void stopGrabber(bool wait_forever = true) {
if (isRunning()) {
stop();
if (wait_forever) waitForFinish();
if (wait_forever)
waitForFinish();
else {
if (!waitForFinish(100)) terminate();
stopRecord();
@@ -106,8 +105,7 @@ public:
}
bool open() {
bool ret = openInternal();
if (!is_opened && ret)
opened();
if (!is_opened && ret) opened();
is_opened = ret;
return ret;
}
@@ -115,11 +113,10 @@ public:
bool em = is_opened;
closeInternal();
last_ = T();
if (em)
closed();
if (em) closed();
is_opened = false;
}
const PIDiagnostics & diag() const {return diag_;}
const PIDiagnostics & diag() const { return diag_; }
void clear() {
que_mutex.lock();
que.clear();
@@ -136,9 +133,9 @@ public:
protected:
virtual void init() {}
virtual bool openInternal() = 0;
virtual bool openInternal() = 0;
virtual void closeInternal() = 0;
virtual int get(T & val) = 0;
virtual int get(T & val) = 0;
virtual void record(const T & val) {}
virtual void startRecordInternal(const PIString & filename) {}
virtual void stopRecordInternal() {}
@@ -147,15 +144,12 @@ protected:
mutable PIMutex rec_mutex;
private:
void begin() override {
init();
}
void begin() override { init(); }
void run() override {
if (!isOpened()) {
open();
diag_.reset();
if (!is_opened)
piMSleep(200);
if (!is_opened) piMSleep(200);
}
if (isOpened()) {
T c;

View File

@@ -1,20 +1,20 @@
/*
PIP - Platform Independent Primitives
PIMutex, PIMutexLocker
Ivan Pelipenko peri4ko@yandex.ru, Stephan Fomenko, Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
PIMutex, PIMutexLocker
Ivan Pelipenko peri4ko@yandex.ru, Stephan Fomenko, Andrey Bychkov work.a.b@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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//! \addtogroup Thread
@@ -108,6 +108,7 @@
#include "pimutex.h"
#include "piincludes_p.h"
#if defined(WINDOWS)
# include <synchapi.h>
@@ -118,16 +119,15 @@
#endif
PRIVATE_DEFINITION_START(PIMutex)
#if defined(WINDOWS)
CRITICAL_SECTION
#elif defined(FREERTOS)
SemaphoreHandle_t
SemaphoreHandle_t
#else
pthread_mutex_t
#endif
mutex;
mutex;
PRIVATE_DEFINITION_END(PIMutex)
@@ -183,21 +183,21 @@ void PIMutex::unlock() {
bool PIMutex::tryLock() {
bool ret =
#if defined(WINDOWS)
(TryEnterCriticalSection(&(PRIVATE->mutex)) != 0);
(TryEnterCriticalSection(&(PRIVATE->mutex)) != 0);
#elif defined(FREERTOS)
xSemaphoreTake(PRIVATE->mutex, 0);
xSemaphoreTake(PRIVATE->mutex, 0);
#else
(pthread_mutex_trylock(&(PRIVATE->mutex)) == 0);
(pthread_mutex_trylock(&(PRIVATE->mutex)) == 0);
#endif
return ret;
}
void * PIMutex::handle() {
void * PIMutex::handle() {
#ifdef FREERTOS
return PRIVATE->mutex;
#else
return (void*)&(PRIVATE->mutex);
return (void *)&(PRIVATE->mutex);
#endif
}

View File

@@ -5,22 +5,22 @@
* \~russian Базовая межпоточная блокировка
*/
/*
PIP - Platform Independent Primitives
PIMutex, PIMutexLocker
Ivan Pelipenko peri4ko@yandex.ru, Stephan Fomenko, Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
PIMutex, PIMutexLocker
Ivan Pelipenko peri4ko@yandex.ru, Stephan Fomenko, Andrey Bychkov work.a.b@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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIMUTEX_H
@@ -29,8 +29,7 @@
#include "piinit.h"
class PIP_EXPORT PIMutex
{
class PIP_EXPORT PIMutex {
public:
NO_COPY_CLASS(PIMutex);
@@ -62,27 +61,28 @@ private:
void destroy();
PRIVATE_DECLARATION(PIP_EXPORT)
};
class PIP_EXPORT PIMutexLocker
{
class PIP_EXPORT PIMutexLocker {
public:
NO_COPY_CLASS(PIMutexLocker);
//! \~english Constructs and lock "m" if "condition" is \c true
//! \~russian Создает и блокирует мьютекс "m" если "condition" \c true
PIMutexLocker(PIMutex & m, bool condition = true): mutex(m), cond(condition) {if (cond) mutex.lock();}
PIMutexLocker(PIMutex & m, bool condition = true): mutex(m), cond(condition) {
if (cond) mutex.lock();
}
//! \~english Unlock "m" if "condition" was \c true
//! \~russian Разблокирует мьютекс "m" если "condition" был \c true
~PIMutexLocker() {if (cond) mutex.unlock();}
~PIMutexLocker() {
if (cond) mutex.unlock();
}
private:
PIMutex & mutex;
bool cond;
};

View File

@@ -5,40 +5,40 @@
* \~russian Класс для создания многопоточного конвейера
*/
/*
PIP - Platform Independent Primitives
Class for create multihread pipeline
Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
Class for create multihread pipeline
Andrey Bychkov work.a.b@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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIPIPELINETHREAD_H
#define PIPIPELINETHREAD_H
#include "pithread.h"
#include "piqueue.h"
#include "piconditionvar.h"
#include "piqueue.h"
#include "pithread.h"
template <typename Tin, typename Tout>
class PIPipelineThread : public PIThread
{
template<typename Tin, typename Tout>
class PIPipelineThread: public PIThread {
PIOBJECT_SUBCLASS(PIPipelineThread, PIThread);
public:
PIPipelineThread() {
cnt = 0;
max_size = 0;
cnt = 0;
max_size = 0;
wait_next_pipe = false;
}
~PIPipelineThread() {
@@ -49,17 +49,18 @@ public:
terminate();
}
}
template <typename T>
template<typename T>
void connectTo(PIPipelineThread<Tout, T> * next) {
CONNECT3(void, Tout, bool, bool *, this, calculated, next, enqueue);
}
EVENT3(calculated, const Tout &, v, bool, wait, bool *, overload);
EVENT_HANDLER3(void, enqueue, const Tin &, v, bool, wait, bool *, overload) {
mutex.lock();
//piCoutObj << "enque" << overload;
// piCoutObj << "enque" << overload;
if (wait && max_size != 0) {
mutex_wait.lock();
while (in.size() >= max_size) cv_wait.wait(mutex_wait);
while (in.size() >= max_size)
cv_wait.wait(mutex_wait);
mutex_wait.unlock();
}
if (max_size == 0 || in.size() < max_size) {
@@ -71,9 +72,9 @@ public:
}
mutex.unlock();
}
void enqueue(const Tin &v, bool wait = false) {enqueue(v, wait, nullptr);}
const ullong * counterPtr() const {return &cnt;}
ullong counter() const {return cnt;}
void enqueue(const Tin & v, bool wait = false) { enqueue(v, wait, nullptr); }
const ullong * counterPtr() const { return &cnt; }
ullong counter() const { return cnt; }
bool isEmpty() {
bool ret;
mutex.lock();
@@ -115,9 +116,7 @@ public:
return ret;
}
uint maxQueSize() {
return max_size;
}
uint maxQueSize() { return max_size; }
void setMaxQueSize(uint count) {
mutex.lock();
@@ -126,16 +125,16 @@ public:
mutex.unlock();
}
bool isWaitNextPipe() {return wait_next_pipe;}
void setWaitNextPipe(bool wait) {wait_next_pipe = wait;}
bool isWaitNextPipe() { return wait_next_pipe; }
void setWaitNextPipe(bool wait) { wait_next_pipe = wait; }
protected:
virtual Tout calc(Tin &v, bool &ok) = 0;
virtual Tout calc(Tin & v, bool & ok) = 0;
uint max_size;
private:
void begin() override {cnt = 0;}
void begin() override { cnt = 0; }
void run() override {
mutex.lock();
while (in.isEmpty()) {
@@ -151,16 +150,16 @@ private:
cv_wait.notifyAll();
mutex_wait.unlock();
bool ok = true;
Tout r = calc(t, ok);
Tout r = calc(t, ok);
if (ok) {
mutex_last.lock();
last = r;
mutex_last.unlock();
cnt++;
//piCoutObj << "calc ok";
// piCoutObj << "calc ok";
calculated(r, wait_next_pipe);
}
//piCoutObj << "run ok";
// piCoutObj << "run ok";
}
PIMutex mutex, mutex_wait;
PIConditionVariable cv, cv_wait;

View File

@@ -1,20 +1,20 @@
/*
PIP - Platform Independent Primitives
PISpinlock
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
PISpinlock
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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//! \addtogroup Thread

View File

@@ -5,39 +5,39 @@
* \~russian Быстрая блокировка с полной нагрузкой
*/
/*
PIP - Platform Independent Primitives
PISpinlock
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
PISpinlock
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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PISPINLOCK_H
#define PISPINLOCK_H
#include "piinit.h"
#include <atomic>
class PIP_EXPORT PISpinlock
{
class PIP_EXPORT PISpinlock {
public:
NO_COPY_CLASS(PISpinlock);
//! \~english Constructs unlocked spinlock
//! \~russian Создает незаблокированный спинлок
explicit PISpinlock() {flag.clear();}
explicit PISpinlock() { flag.clear(); }
//! \~english Destroy spinlock
//! \~russian Деструктор спинлока
@@ -53,7 +53,10 @@ public:
//! \~russian
//! Если спинлок свободен, то блокирует его и возвращает управление немедленно.
//! Если спинлок заблокирован, то ожидает разблокировки, затем блокирует и возвращает управление
void lock() {while (flag.test_and_set(std::memory_order_acquire));}
void lock() {
while (flag.test_and_set(std::memory_order_acquire))
;
}
//! \~english Unlock spinlock
//! \~russian Разблокирует спинлок
@@ -62,31 +65,32 @@ public:
//! In any case this function returns immediate
//! \~russian
//! В любом случае возвращает управление немедленно
void unlock() {flag.clear(std::memory_order_release);}
void unlock() { flag.clear(std::memory_order_release); }
private:
std::atomic_flag flag;
};
class PIP_EXPORT PISpinlockLocker
{
class PIP_EXPORT PISpinlockLocker {
public:
NO_COPY_CLASS(PISpinlockLocker);
//! \~english Constructs and lock "s" if "condition" is \c true
//! \~russianСоздает и блокирует спинлок "m" если "condition" \c true
PISpinlockLocker(PISpinlock & s, bool condition = true): spinlock(s), cond(condition) {if (cond) spinlock.lock();}
PISpinlockLocker(PISpinlock & s, bool condition = true): spinlock(s), cond(condition) {
if (cond) spinlock.lock();
}
//! \~english Unlock "s" if "condition" was \c true
//! \~russian Разблокирует спинлок "m" если "condition" был \c true
~PISpinlockLocker() {if (cond) spinlock.unlock();}
~PISpinlockLocker() {
if (cond) spinlock.unlock();
}
private:
PISpinlock & spinlock;
bool cond;
};

View File

@@ -1,24 +1,25 @@
/*
PIP - Platform Independent Primitives
Thread
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
Thread
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piincludes_p.h"
#include "pithread.h"
#include "piincludes_p.h"
#include "piintrospection_threads.h"
#include "pitime.h"
#ifndef MICRO_PIP
@@ -33,7 +34,7 @@
#elif defined(FREERTOS)
# define __THREAD_FUNC_RET__ void
#else
# define __THREAD_FUNC_RET__ void*
# define __THREAD_FUNC_RET__ void *
#endif
#ifndef FREERTOS
# define __THREAD_FUNC_END__ 0
@@ -47,11 +48,17 @@
#if defined(MAC_OS) || defined(BLACKBERRY)
# include <pthread.h>
#endif
__THREAD_FUNC_RET__ thread_function(void * t) {((PIThread*)t)->__thread_func__(); return __THREAD_FUNC_END__;}
__THREAD_FUNC_RET__ thread_function_once(void * t) {((PIThread*)t)->__thread_func_once__(); return __THREAD_FUNC_END__;}
__THREAD_FUNC_RET__ thread_function(void * t) {
((PIThread *)t)->__thread_func__();
return __THREAD_FUNC_END__;
}
__THREAD_FUNC_RET__ thread_function_once(void * t) {
((PIThread *)t)->__thread_func_once__();
return __THREAD_FUNC_END__;
}
#ifndef MICRO_PIP
# define REGISTER_THREAD(t) __PIThreadCollection::instance()->registerThread(t)
# define REGISTER_THREAD(t) __PIThreadCollection::instance()->registerThread(t)
# define UNREGISTER_THREAD(t) __PIThreadCollection::instance()->unregisterThread(t)
#else
# define REGISTER_THREAD(t)
@@ -449,15 +456,14 @@ __THREAD_FUNC_RET__ thread_function_once(void * t) {((PIThread*)t)->__thread_fun
#ifndef MICRO_PIP
__PIThreadCollection *__PIThreadCollection::instance() {
__PIThreadCollection * __PIThreadCollection::instance() {
return __PIThreadCollection_Initializer__::__instance__;
}
void __PIThreadCollection::registerThread(PIThread * t) {
lock();
if (!threads_.contains(t))
threads_ << t;
if (!threads_.contains(t)) threads_ << t;
unlock();
}
@@ -469,7 +475,7 @@ void __PIThreadCollection::unregisterThread(PIThread * t) {
}
PIVector<PIThread * > __PIThreadCollection::threads() const {
PIVector<PIThread *> __PIThreadCollection::threads() const {
return threads_;
}
@@ -490,26 +496,24 @@ void __PIThreadCollection::stoppedAuto() {
}
int __PIThreadCollection_Initializer__::count_(0);
__PIThreadCollection * __PIThreadCollection_Initializer__::__instance__(0);
__PIThreadCollection_Initializer__::__PIThreadCollection_Initializer__() {
count_++;
//PICout(PICoutManipulators::DefaultControls) << "try create Core" << count_;
// PICout(PICoutManipulators::DefaultControls) << "try create Core" << count_;
if (count_ > 1) return;
//PICout(PICoutManipulators::DefaultControls) << "create Core";
// PICout(PICoutManipulators::DefaultControls) << "create Core";
__instance__ = new __PIThreadCollection();
}
__PIThreadCollection_Initializer__::~__PIThreadCollection_Initializer__() {
count_--;
//PICout(PICoutManipulators::DefaultControls) << "try delete Core" << count_;
// PICout(PICoutManipulators::DefaultControls) << "try delete Core" << count_;
if (count_ > 0) return;
//PICout(PICoutManipulators::DefaultControls) << "delete Core";
// PICout(PICoutManipulators::DefaultControls) << "delete Core";
if (__instance__ != 0) {
delete __instance__;
__instance__ = 0;
@@ -533,38 +537,38 @@ PRIVATE_DEFINITION_END(PIThread)
PIThread::PIThread(void * data, ThreadFunc func, bool startNow, int timer_delay): PIObject() {
PIINTROSPECTION_THREAD_NEW(this);
tid_ = -1;
tid_ = -1;
PRIVATE->thread = 0;
data_ = data;
ret_func = func;
data_ = data;
ret_func = func;
terminating = running_ = lockRun = false;
priority_ = piNormal;
delay_ = timer_delay;
priority_ = piNormal;
delay_ = timer_delay;
if (startNow) start(timer_delay);
}
PIThread::PIThread(std::function<void ()> func, bool startNow, int timer_delay) {
PIThread::PIThread(std::function<void()> func, bool startNow, int timer_delay) {
PIINTROSPECTION_THREAD_NEW(this);
tid_ = -1;
tid_ = -1;
PRIVATE->thread = 0;
data_ = 0;
ret_func = [func](void*){func();};
data_ = 0;
ret_func = [func](void *) { func(); };
terminating = running_ = lockRun = false;
priority_ = piNormal;
delay_ = timer_delay;
priority_ = piNormal;
delay_ = timer_delay;
if (startNow) start(timer_delay);
}
PIThread::PIThread(bool startNow, int timer_delay): PIObject() {
PIINTROSPECTION_THREAD_NEW(this);
tid_ = -1;
tid_ = -1;
PRIVATE->thread = 0;
ret_func = 0;
ret_func = 0;
terminating = running_ = lockRun = false;
priority_ = piNormal;
delay_ = timer_delay;
priority_ = piNormal;
delay_ = timer_delay;
if (startNow) start(timer_delay);
}
@@ -573,19 +577,19 @@ PIThread::~PIThread() {
PIINTROSPECTION_THREAD_DELETE(this);
if (!running_ || PRIVATE->thread == 0) return;
#ifdef FREERTOS
//void * ret(0);
//PICout(PICoutManipulators::DefaultControls) << "~PIThread" << PRIVATE->thread;
//PICout(PICoutManipulators::DefaultControls) << pthread_join(PRIVATE->thread, 0);
// void * ret(0);
// PICout(PICoutManipulators::DefaultControls) << "~PIThread" << PRIVATE->thread;
// PICout(PICoutManipulators::DefaultControls) << pthread_join(PRIVATE->thread, 0);
PICout(PICoutManipulators::DefaultControls) << "FreeRTOS can't terminate pthreads! waiting for stop";
stop(true);
//PICout(PICoutManipulators::DefaultControls) << "stopped!";
// PICout(PICoutManipulators::DefaultControls) << "stopped!";
#else
#ifndef WINDOWS
# ifdef ANDROID
# ifndef WINDOWS
# ifdef ANDROID
pthread_kill(PRIVATE->thread, SIGTERM);
# else
# else
pthread_cancel(PRIVATE->thread);
# endif
# endif
# else
TerminateThread(PRIVATE->thread, 0);
CloseHandle(PRIVATE->thread);
@@ -602,7 +606,7 @@ void PIThread::stopAndWait(int timeout_ms) {
void PIThread::stop() {
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop ..." << running_ << wait;
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop ..." << running_ << wait;
terminating = true;
}
@@ -610,46 +614,46 @@ void PIThread::stop() {
bool PIThread::start(int timer_delay) {
if (running_) return false;
delay_ = timer_delay;
return _startThread((void*)thread_function);
return _startThread((void *)thread_function);
}
bool PIThread::startOnce() {
if (running_) return false;
return _startThread((void*)thread_function_once);
return _startThread((void *)thread_function_once);
}
void PIThread::terminate() {
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "terminate ..." << running_;
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "terminate ..." << running_;
#ifdef FREERTOS
PICout(PICoutManipulators::DefaultControls) << "FreeRTOS can't terminate pthreads! waiting for stop";
stop(true);
//PICout(PICoutManipulators::DefaultControls) << "stopped!";
// PICout(PICoutManipulators::DefaultControls) << "stopped!";
#else
if (PRIVATE->thread == 0) return;
UNREGISTER_THREAD(this);
terminating = running_ = false;
tid_ = -1;
//PICout(PICoutManipulators::DefaultControls) << "terminate" << PRIVATE->thread;
tid_ = -1;
// PICout(PICoutManipulators::DefaultControls) << "terminate" << PRIVATE->thread;
# ifndef WINDOWS
# ifdef ANDROID
# ifdef ANDROID
pthread_kill(PRIVATE->thread, SIGTERM);
# else
//pthread_kill(PRIVATE->thread, SIGKILL);
//void * ret(0);
# else
// pthread_kill(PRIVATE->thread, SIGKILL);
// void * ret(0);
pthread_cancel(PRIVATE->thread);
//pthread_join(PRIVATE->thread, &ret);
# endif
// pthread_join(PRIVATE->thread, &ret);
# endif
# else
TerminateThread(PRIVATE->thread, 0);
CloseHandle(PRIVATE->thread);
# endif
PRIVATE->thread = 0;
end();
#endif //FREERTOS
#endif // FREERTOS
PIINTROSPECTION_THREAD_STOP(this);
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "terminate ok" << running_;
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "terminate ok" << running_;
}
@@ -688,207 +692,206 @@ int PIThread::priority2System(PIThread::Priority p) {
bool PIThread::_startThread(void * func) {
terminating = false;
running_ = true;
running_ = true;
#if !defined(WINDOWS) && !defined(FREERTOS)
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
int ret = pthread_create(&PRIVATE->thread, &attr, (__THREAD_FUNC_RET__(*)(void*))func, this);
//PICout(PICoutManipulators::DefaultControls) << "pthread_create" << PRIVATE->thread;
int ret = pthread_create(&PRIVATE->thread, &attr, (__THREAD_FUNC_RET__(*)(void *))func, this);
// PICout(PICoutManipulators::DefaultControls) << "pthread_create" << PRIVATE->thread;
pthread_attr_destroy(&attr);
if (ret == 0) {
# ifdef MAC_OS
pthread_setname_np(((PIString&)name().elided(15, 0.4f).resize(15, PIChar('\0'))).dataAscii());
pthread_threadid_np(PRIVATE->thread, (__uint64_t*)&tid_);
pthread_setname_np(((PIString &)name().elided(15, 0.4f).resize(15, PIChar('\0'))).dataAscii());
pthread_threadid_np(PRIVATE->thread, (__uint64_t *)&tid_);
# else
pthread_setname_np(PRIVATE->thread, ((PIString&)name().elided(15, 0.4f).resize(15, PIChar('\0'))).dataAscii());
pthread_setname_np(PRIVATE->thread, ((PIString &)name().elided(15, 0.4f).resize(15, PIChar('\0'))).dataAscii());
# endif
#endif
#ifdef WINDOWS
if (PRIVATE->thread) CloseHandle(PRIVATE->thread);
if (PRIVATE->thread) CloseHandle(PRIVATE->thread);
# ifdef CC_GCC
PRIVATE->thread = (void *)_beginthreadex(0, 0, (__THREAD_FUNC_RET__(*)(void*))func, this, 0, 0);
PRIVATE->thread = (void *)_beginthreadex(0, 0, (__THREAD_FUNC_RET__(*)(void *))func, this, 0, 0);
# else
PRIVATE->thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)func, this, 0, 0);
PRIVATE->thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)func, this, 0, 0);
# endif
if (PRIVATE->thread != 0) {
if (PRIVATE->thread != 0) {
#endif
#ifdef FREERTOS
if (xTaskCreate(
(__THREAD_FUNC_RET__(*)(void*))func,
((PIString&)name().elided(15, 0.4f).resize(15, PIChar('\0'))).dataAscii(), // A name just for humans
128, // This stack size can be checked & adjusted by reading the Stack Highwater
this,
priority_,
&PRIVATE->thread
) == pdPASS) {
tid_ = (llong)PRIVATE->thread;
if (xTaskCreate((__THREAD_FUNC_RET__(*)(void *))func,
((PIString &)name().elided(15, 0.4f).resize(15, PIChar('\0'))).dataAscii(), // A name just for humans
128, // This stack size can be checked & adjusted by reading the Stack Highwater
this,
priority_,
&PRIVATE->thread) == pdPASS) {
tid_ = (llong)PRIVATE->thread;
#endif
#ifndef FREERTOS
setPriority(priority_);
setPriority(priority_);
#endif
return true;
} else {
running_ = false;
PRIVATE->thread = 0;
piCoutObj << "Error: Can`t start new thread:" << errorString();
}
running_ = false;
return false;
}
return true;
} else {
running_ = false;
PRIVATE->thread = 0;
piCoutObj << "Error: Can`t start new thread:" << errorString();
}
running_ = false;
return false;
}
void PIThread::setPriority(PIThread::Priority prior) {
priority_ = prior;
if (!running_ || (PRIVATE->thread == 0)) return;
void PIThread::setPriority(PIThread::Priority prior) {
priority_ = prior;
if (!running_ || (PRIVATE->thread == 0)) return;
#ifdef FREERTOS
vTaskPrioritySet(PRIVATE->thread, priority2System(priority_));
vTaskPrioritySet(PRIVATE->thread, priority2System(priority_));
#else
# ifndef WINDOWS
//PICout(PICoutManipulators::DefaultControls) << "setPriority" << PRIVATE->thread;
// PICout(PICoutManipulators::DefaultControls) << "setPriority" << PRIVATE->thread;
policy_ = 0;
memset(&(PRIVATE->sparam), 0, sizeof(PRIVATE->sparam));
pthread_getschedparam(PRIVATE->thread, &policy_, &(PRIVATE->sparam));
PRIVATE->sparam.
# ifndef LINUX
sched_priority
# else
__sched_priority
# endif
= priority2System(priority_);
# ifndef LINUX
sched_priority
# else
__sched_priority
# endif
= priority2System(priority_);
pthread_setschedparam(PRIVATE->thread, policy_, &(PRIVATE->sparam));
# else
if (!running_ || (PRIVATE->thread == 0)) return;
SetThreadPriority(PRIVATE->thread, priority2System(priority_));
# endif
#endif //FREERTOS
}
#endif // FREERTOS
}
#ifdef WINDOWS
bool isExists(HANDLE hThread) {
//errorClear();
//piCout << "isExists" << hThread;
DWORD dw = 0;
GetExitCodeThread(hThread, &dw);
//piCout << ret << dw << errorString();
if (dw == STILL_ACTIVE) return true;
//piCout << errorString();
return false;
}
bool isExists(HANDLE hThread) {
// errorClear();
// piCout << "isExists" << hThread;
DWORD dw = 0;
GetExitCodeThread(hThread, &dw);
// piCout << ret << dw << errorString();
if (dw == STILL_ACTIVE) return true;
// piCout << errorString();
return false;
}
#endif
bool PIThread::waitForFinish(int timeout_msecs) {
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "PIThread::waitForFinish" << running_ << terminating << timeout_msecs;
if (!running_) return true;
if (timeout_msecs < 0) {
while (running_) {
piMinSleep();
bool PIThread::waitForFinish(int timeout_msecs) {
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "PIThread::waitForFinish" << running_ << terminating <<
// timeout_msecs;
if (!running_) return true;
if (timeout_msecs < 0) {
while (running_) {
piMinSleep();
#ifdef WINDOWS
if (!isExists(PRIVATE->thread)) {
unlock();
if (!isExists(PRIVATE->thread)) {
unlock();
return true;
}
#endif
}
return true;
}
#endif
}
return true;
}
tmf_.reset();
while (running_ && tmf_.elapsed_m() < timeout_msecs) {
piMinSleep();
tmf_.reset();
while (running_ && tmf_.elapsed_m() < timeout_msecs) {
piMinSleep();
#ifdef WINDOWS
if (!isExists(PRIVATE->thread)) {
unlock();
return true;
}
if (!isExists(PRIVATE->thread)) {
unlock();
return true;
}
#endif
}
return tmf_.elapsed_m() < timeout_msecs;
}
}
return tmf_.elapsed_m() < timeout_msecs;
}
bool PIThread::waitForStart(int timeout_msecs) {
if (running_) return true;
if (timeout_msecs < 0) {
while (!running_)
piMinSleep();
return true;
}
tms_.reset();
while (!running_ && tms_.elapsed_m() < timeout_msecs)
piMinSleep();
return tms_.elapsed_m() < timeout_msecs;
}
bool PIThread::waitForStart(int timeout_msecs) {
if (running_) return true;
if (timeout_msecs < 0) {
while (!running_)
piMinSleep();
return true;
}
tms_.reset();
while (!running_ && tms_.elapsed_m() < timeout_msecs)
piMinSleep();
return tms_.elapsed_m() < timeout_msecs;
}
void PIThread::_beginThread() {
void PIThread::_beginThread() {
#ifndef WINDOWS
# if !defined(ANDROID) && !defined(FREERTOS)
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, 0);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, 0);
# endif
#endif
#ifdef WINDOWS
tid_ = GetCurrentThreadId();
tid_ = GetCurrentThreadId();
#endif
#ifdef LINUX
tid_ = gettid();
tid_ = gettid();
#endif
PIINTROSPECTION_THREAD_START(this);
REGISTER_THREAD(this);
running_ = true;
if (lockRun) thread_mutex.lock();
begin();
if (lockRun) thread_mutex.unlock();
started();
}
PIINTROSPECTION_THREAD_START(this);
REGISTER_THREAD(this);
running_ = true;
if (lockRun) thread_mutex.lock();
begin();
if (lockRun) thread_mutex.unlock();
started();
}
void PIThread::_runThread() {
PIINTROSPECTION_THREAD_RUN(this);
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "...";
if (lockRun) thread_mutex.lock();
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "ok";
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "run" << "...";
void PIThread::_runThread() {
PIINTROSPECTION_THREAD_RUN(this);
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "...";
if (lockRun) thread_mutex.lock();
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "ok";
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "run" << "...";
#ifdef PIP_INTROSPECTION
PITimeMeasurer _tm;
PITimeMeasurer _tm;
#endif
run();
run();
#ifdef PIP_INTROSPECTION
PIINTROSPECTION_THREAD_RUN_DONE(this, ullong(_tm.elapsed_u()));
PIINTROSPECTION_THREAD_RUN_DONE(this, ullong(_tm.elapsed_u()));
#endif
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "run" << "ok";
//printf("thread %p tick\n", this);
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "ret_func" << "...";
if (ret_func != 0) ret_func(data_);
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "ret_func" << "ok";
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "unlock" << "...";
if (lockRun) thread_mutex.unlock();
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "unlock" << "ok";
}
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "run" << "ok";
// printf("thread %p tick\n", this);
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "ret_func" << "...";
if (ret_func != 0) ret_func(data_);
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "ret_func" << "ok";
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "unlock" << "...";
if (lockRun) thread_mutex.unlock();
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "unlock" << "ok";
}
void PIThread::_endThread() {
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "...";
stopped();
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
if (lockRun) thread_mutex.lock();
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "end" << "...";
end();
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
if (lockRun) thread_mutex.unlock();
terminating = running_ = false;
tid_ = -1;
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "exit";
//cout << "thread " << t << " exiting ... " << endl;
//PICout(PICoutManipulators::DefaultControls) << "pthread_exit" << (__privateinitializer__.p)->thread;
UNREGISTER_THREAD(this);
PIINTROSPECTION_THREAD_STOP(this);
void PIThread::_endThread() {
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "...";
stopped();
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
if (lockRun) thread_mutex.lock();
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "end" << "...";
end();
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
if (lockRun) thread_mutex.unlock();
terminating = running_ = false;
tid_ = -1;
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "exit";
// cout << "thread " << t << " exiting ... " << endl;
// PICout(PICoutManipulators::DefaultControls) << "pthread_exit" << (__privateinitializer__.p)->thread;
UNREGISTER_THREAD(this);
PIINTROSPECTION_THREAD_STOP(this);
#if defined(WINDOWS)
# ifdef CC_GCC
_endthreadex(0);
_endthreadex(0);
# else
ExitThread(0);
ExitThread(0);
# endif
#elif defined(FREERTOS)
PRIVATE->thread = 0;
@@ -897,116 +900,115 @@ void PIThread::_endThread() {
PRIVATE->thread = 0;
pthread_exit(0);
#endif
}
void PIThread::__thread_func__() {
_beginThread();
while (!terminating) {
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "queued" << "...";
maybeCallQueuedEvents();
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "queued" << "ok";
_runThread();
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "wait" << "...";
PIINTROSPECTION_THREAD_WAIT(this);
if (delay_ > 0) {
tmr_.reset();
double sl(0.);
while (1) {
sl = piMind(delay_ - tmr_.elapsed_m(), PIP_MIN_MSLEEP);
if (terminating) break;
if (sl <= 0.) break;
piMSleep(sl);
}
}
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "wait" << "ok";
}
_endThread();
}
void PIThread::__thread_func_once__() {
_beginThread();
_runThread();
_endThread();
}
void PIThread::__thread_func__() {
_beginThread();
while (!terminating) {
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "queued" << "...";
maybeCallQueuedEvents();
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "queued" << "ok";
_runThread();
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "wait" << "...";
PIINTROSPECTION_THREAD_WAIT(this);
if (delay_ > 0) {
tmr_.reset();
double sl(0.);
while (1) {
sl = piMind(delay_ - tmr_.elapsed_m(), PIP_MIN_MSLEEP);
if (terminating) break;
if (sl <= 0.) break;
piMSleep(sl);
}
}
// PICout(PICoutManipulators::DefaultControls) << "thread" << this << "wait" << "ok";
}
_endThread();
}
//! \~\details
//! \~english
//! This method create %PIThread with name "name" and execute
//! event handler "handler" of object "object" in this thread.\n
//! This %PIThread automatically delete on function finish.
//!
//! \~russian
//! Этот метод создает %PIThread с именем "name" и выполняет
//! обработчик "handler" объекта "object" в этом потоке.\n
//! %PIThread автоматически удаляется после завершения обработчика.
//!
//! \~\code
//! class MyObj: public PIObject {
//! PIOBJECT(MyObj)
//! public:
//! EVENT_HANDLER(void, threadRun) {
//! piForTimes (5) {
//! piCout << "threadRun";
//! piMSleep(100);
//! }
//! };
//! };
//!
//! int main(int argc, char * argv[]) {
//! MyObj mo;
//! PIThread::runOnce(&mo, "threadRun");
//! piMSleep(1000); // wait for thread finish
//! return 0;
//! }
//! \endcode
void PIThread::runOnce(PIObject * object, const char * handler, const PIString & name) {
PIThread * t = new PIThread();
t->setName(name);
if (!PIObject::piConnectU(t, PIStringAscii("started"), object, object, PIStringAscii(handler), "PIThread::runOnce").isValid()) {
delete t;
return;
}
void PIThread::__thread_func_once__() {
_beginThread();
_runThread();
_endThread();
}
//! \~\details
//! \~english
//! This method create %PIThread with name "name" and execute
//! event handler "handler" of object "object" in this thread.\n
//! This %PIThread automatically delete on function finish.
//!
//! \~russian
//! Этот метод создает %PIThread с именем "name" и выполняет
//! обработчик "handler" объекта "object" в этом потоке.\n
//! %PIThread автоматически удаляется после завершения обработчика.
//!
//! \~\code
//! class MyObj: public PIObject {
//! PIOBJECT(MyObj)
//! public:
//! EVENT_HANDLER(void, threadRun) {
//! piForTimes (5) {
//! piCout << "threadRun";
//! piMSleep(100);
//! }
//! };
//! };
//!
//! int main(int argc, char * argv[]) {
//! MyObj mo;
//! PIThread::runOnce(&mo, "threadRun");
//! piMSleep(1000); // wait for thread finish
//! return 0;
//! }
//! \endcode
void PIThread::runOnce(PIObject * object, const char * handler, const PIString & name) {
PIThread * t = new PIThread();
t->setName(name);
if (!PIObject::piConnectU(t, PIStringAscii("started"), object, object, PIStringAscii(handler), "PIThread::runOnce").isValid()) {
delete t;
return;
}
#ifndef MICRO_PIP
__PIThreadCollection::instance()->startedAuto(t);
CONNECT0(void, t, stopped, __PIThreadCollection::instance(), stoppedAuto);
__PIThreadCollection::instance()->startedAuto(t);
CONNECT0(void, t, stopped, __PIThreadCollection::instance(), stoppedAuto);
#endif
t->startOnce();
}
t->startOnce();
}
//! \~\details
//! \~english
//! This method create %PIThread with name "name" and execute
//! [lambda expression](https://en.cppreference.com/w/cpp/language/lambda) "func" in this thread.\n
//! This %PIThread automatically delete on function finish.\n
//! "func" shouldn`t have arguments.
//!
//! \~russian
//! Этот метод создает %PIThread с именем "name" и выполняет
//! [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda) "func" в этом потоке.\n
//! %PIThread автоматически удаляется после завершения функции.\n
//! "func" не должна иметь аргументов.
//!
//! \~\code
//! PIThread::runOnce([](){
//! piForTimes(5) {
//! piCout << "thread func";
//! piMSleep(100);
//! }
//! });
//! piMSleep(1000);
//! \endcode
void PIThread::runOnce(std::function<void ()> func, const PIString & name) {
PIThread * t = new PIThread();
t->setName(name);
t->setSlot(func);
//! \~\details
//! \~english
//! This method create %PIThread with name "name" and execute
//! [lambda expression](https://en.cppreference.com/w/cpp/language/lambda) "func" in this thread.\n
//! This %PIThread automatically delete on function finish.\n
//! "func" shouldn`t have arguments.
//!
//! \~russian
//! Этот метод создает %PIThread с именем "name" и выполняет
//! [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda) "func" в этом потоке.\n
//! %PIThread автоматически удаляется после завершения функции.\n
//! "func" не должна иметь аргументов.
//!
//! \~\code
//! PIThread::runOnce([](){
//! piForTimes(5) {
//! piCout << "thread func";
//! piMSleep(100);
//! }
//! });
//! piMSleep(1000);
//! \endcode
void PIThread::runOnce(std::function<void()> func, const PIString & name) {
PIThread * t = new PIThread();
t->setName(name);
t->setSlot(func);
#ifndef MICRO_PIP
__PIThreadCollection::instance()->startedAuto(t);
CONNECT0(void, t, stopped, __PIThreadCollection::instance(), stoppedAuto);
__PIThreadCollection::instance()->startedAuto(t);
CONNECT0(void, t, stopped, __PIThreadCollection::instance(), stoppedAuto);
#endif
t->startOnce();
}
t->startOnce();
}

View File

@@ -5,22 +5,22 @@
* \~russian Класс потока
*/
/*
PIP - Platform Independent Primitives
Thread
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
Thread
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PITHREAD_H
@@ -37,17 +37,19 @@ class PIIntrospectionThreads;
class PIP_EXPORT __PIThreadCollection: public PIObject {
PIOBJECT(__PIThreadCollection)
public:
static __PIThreadCollection * instance();
void registerThread(PIThread * t);
void unregisterThread(PIThread * t);
PIVector<PIThread * > threads() const;
void lock() {mutex.lock();}
void unlock() {mutex.unlock();}
PIVector<PIThread *> threads() const;
void lock() { mutex.lock(); }
void unlock() { mutex.unlock(); }
void startedAuto(PIThread * t);
EVENT_HANDLER(void, stoppedAuto);
private:
PIVector<PIThread * > threads_, auto_threads_;
PIVector<PIThread *> threads_, auto_threads_;
mutable PIMutex mutex, auto_mutex;
};
@@ -66,12 +68,12 @@ static __PIThreadCollection_Initializer__ __PIThreadCollection_initializer__;
typedef std::function<void(void *)> ThreadFunc;
class PIP_EXPORT PIThread: public PIObject
{
class PIP_EXPORT PIThread: public PIObject {
PIOBJECT_SUBCLASS(PIThread, PIObject);
#ifndef MICRO_PIP
friend class PIIntrospectionThreads;
#endif
public:
NO_COPY_CLASS(PIThread);
@@ -86,86 +88,99 @@ public:
//! \~english Contructs thread with main loop delay "loop_delay"
//! \~russian Создает поток с задержкой цикла "loop_delay"
PIThread(bool startNow = false, int loop_delay = -1);
virtual ~PIThread();
//! \~english Priority of thread
//! \~russian Приоритет потока
enum Priority {
piLowerst /** \~english Lowest \~russian Низший */ ,
piLow /** \~english Low \~russian Низкий */ ,
piNormal /** \~english Normal, this is default priority of threads and timers \~russian Нормальный, это приоритет по умолчанию для потоков и таймеров */ ,
piHigh /** \~english High \~russian Высокий */ ,
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);}
EVENT_HANDLER0(bool, start) { return start(-1); }
EVENT_HANDLER1(bool, start, int, timer_delay);
bool start(ThreadFunc func) {return start(func, -1);}
bool start(ThreadFunc func, int timer_delay) {ret_func = func; return start(timer_delay);}
bool start(std::function<void()> func) {return start(func, -1);}
bool start(std::function<void()> func, int timer_delay) {ret_func = [func](void*){func();}; return start(timer_delay);}
bool start(ThreadFunc func) { return start(func, -1); }
bool start(ThreadFunc func, int timer_delay) {
ret_func = func;
return start(timer_delay);
}
bool start(std::function<void()> func) { return start(func, -1); }
bool start(std::function<void()> func, int timer_delay) {
ret_func = [func](void *) { func(); };
return start(timer_delay);
}
EVENT_HANDLER0(bool, startOnce);
EVENT_HANDLER1(bool, startOnce, ThreadFunc, func) {ret_func = func; return startOnce();}
EVENT_HANDLER1(bool, startOnce, ThreadFunc, func) {
ret_func = func;
return startOnce();
}
EVENT_HANDLER0(void, stop);
EVENT_HANDLER0(void, terminate);
//! \~english Stop thread and wait for finish.
//! \~russian Останавливает поток и ожидает завершения.
void stopAndWait(int timeout_ms = -1);
//! \~english Set common data passed to external function
//! \~russian Устанавливает данные, передаваемые в функцию потока
void setData(void * d) {data_ = d;}
void setData(void * d) { data_ = d; }
//! \~english Set external function that will be executed after every \a run()
//! \~russian Устанавливает функцию потока, вызываемую после каждого \a run()
void setSlot(ThreadFunc func) {ret_func = func;}
void setSlot(ThreadFunc func) { ret_func = func; }
//! \~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();};}
void setSlot(std::function<void()> func) {
ret_func = [func](void *) { func(); };
}
//! \~english Set thread priority
//! \~russian Устанавливает приоритет потока
void setPriority(PIThread::Priority prior);
//! \~english Returns common data passed to external function
//! \~russian Возвращает данные, передаваемые в функцию потока
void * data() const {return data_;}
void * data() const { return data_; }
//! \~english Return thread priority
//! \~russian Возвращает приоритет потока
PIThread::Priority priority() const {return priority_;}
PIThread::Priority priority() const { return priority_; }
//! \~english Return if thread is running
//! \~russian Возвращает исполняется ли поток
bool isRunning() const {return running_;}
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);}
bool isStopping() const { return running_ && terminating; }
EVENT_HANDLER0(bool, waitForStart) { return waitForStart(-1); }
EVENT_HANDLER1(bool, waitForStart, int, timeout_msecs);
EVENT_HANDLER0(bool, waitForFinish) {return waitForFinish(-1);}
EVENT_HANDLER0(bool, waitForFinish) { return waitForFinish(-1); }
EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs);
//! \~english Set necessity of lock every \a run() with internal mutex
//! \~russian Устанавливает необходимость блокировки внутреннего мьютекса каждый \a run()
void needLockRun(bool need) {lockRun = need;}
void needLockRun(bool need) { lockRun = need; }
EVENT_HANDLER0(void, lock) const {thread_mutex.lock();}
EVENT_HANDLER0(void, unlock) const {thread_mutex.unlock();}
EVENT_HANDLER0(void, lock) const { thread_mutex.lock(); }
EVENT_HANDLER0(void, unlock) const { thread_mutex.unlock(); }
//! \~english Returns internal mutex
//! \~russian Возвращает внутренний мьютекс
PIMutex & mutex() const {return thread_mutex;}
PIMutex & mutex() const { return thread_mutex; }
//! \~english Returns thread ID
//! \~russian Возвращает ID потока
llong tid() const {return tid_;}
llong tid() const { return tid_; }
void __thread_func__();
void __thread_func_once__();
@@ -180,44 +195,44 @@ public:
//! \~russian Вызывает [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda) "func" в отдельном потоке
static void runOnce(std::function<void()> func, const PIString & name = PIString());
//! \handlers
//! \{
//! \handlers
//! \{
//! \fn bool start(int timer_delay = -1)
//! \brief
//! \~english Start thread
//! \~russian Запускает поток
//! \fn bool startOnce()
//! \brief
//! \~english Start thread without internal loop
//! \~russian Запускает поток без внутреннего цикла
//! \fn bool startOnce(ThreadFunc func)
//! \brief
//! \~english Start thread without internal loop
//! \~russian Запускает поток без внутреннего цикла
//! \fn void stop()
//! \brief
//! \~english Stop thread
//! \~russian Останавливает поток
//! \fn void terminate()
//! \brief
//! \~english Strongly stop thread
//! \~russian Жёстко прерывает поток
//! \fn bool waitForStart(int timeout_msecs = -1)
//! \brief
//! \~english Wait for thread start
//! \~russian Ожидает старта потока
//! \fn bool waitForFinish(int timeout_msecs = -1)
//! \brief
//! \~english Wait for thread finish
//! \~russian Ожидает завершения потока
//! \fn void lock()
//! \brief
//! \~english Lock internal mutex
@@ -228,10 +243,10 @@ public:
//! \~english Unlock internal mutex
//! \~russian Разблокирует внутренний мьютекс
//! \}
//! \events
//! \{
//! \}
//! \events
//! \{
//! \fn void started()
//! \brief
//! \~english Raise on thread start
@@ -242,22 +257,22 @@ public:
//! \~english Raise on thread stop
//! \~russian Вызывается при завершении потока
//! \}
//! \}
protected:
static int priority2System(PIThread::Priority p);
//! \~english Function executed once at the start of thread
//! \~russian Метод выполняется один раз при старте потока
virtual void begin() {;}
virtual void begin() { ; }
//! \~english Function executed at every "timer_delay" msecs until thread was stopped
//! \~russian Метод выполняется каждые "timer_delay" миллисекунд
virtual void run() {;}
virtual void run() { ; }
//! \~english Function executed once at the end of thread
//! \~russian Метод выполняется один раз при остановке потока
virtual void end() {;}
virtual void end() { ; }
std::atomic_bool terminating, running_, lockRun;
int delay_, policy_;
@@ -274,7 +289,6 @@ private:
void _beginThread();
void _runThread();
void _endThread();
};

View File

@@ -1,20 +1,20 @@
/*
PIP - Platform Independent Primitives
Module includes
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
Module includes
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//! \defgroup Thread Thread
//! \~\brief
@@ -51,15 +51,15 @@
#ifndef PITHREADMODULE_H
#define PITHREADMODULE_H
#include "piconditionvar.h"
#include "pigrabberbase.h"
#include "pimutex.h"
#include "pipipelinethread.h"
#include "pispinlock.h"
#include "pithread.h"
#include "pitimer.h"
#include "pipipelinethread.h"
#include "pigrabberbase.h"
#include "piconditionvar.h"
#include "pithreadnotifier.h"
#include "pithreadpoolexecutor.h"
#include "pithreadpoolloop.h"
#include "pithreadnotifier.h"
#include "pitimer.h"
#endif // PITHREADMODULE_H

View File

@@ -1,20 +1,20 @@
/*
PIP - Platform Independent Primitives
Class for simply notify and wait in different threads
Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
Class for simply notify and wait in different threads
Andrey Bychkov work.a.b@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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pithreadnotifier.h"
@@ -36,7 +36,7 @@
//! syncronize some actions in several threads.
//!
//! \~russian
//!Этот класс используется как событийный механизм между потоками.
//! Этот класс используется как событийный механизм между потоками.
//! Один поток ждёт некоторого события и другой его отправляет, разблокируя первый.
//! Это полезно для синхронизации действий в нескольких потоках.
//!
@@ -88,7 +88,7 @@
//! \}
PIThreadNotifier::PIThreadNotifier() : cnt(0) {}
PIThreadNotifier::PIThreadNotifier(): cnt(0) {}
//! \~\details
@@ -108,7 +108,8 @@ PIThreadNotifier::PIThreadNotifier() : cnt(0) {}
//!
void PIThreadNotifier::wait() {
m.lock();
while (cnt == 0) v.wait(m);
while (cnt == 0)
v.wait(m);
cnt--;
m.unlock();
}

View File

@@ -5,22 +5,22 @@
* \~russian Класс для простого уведомления и ожидания в различных потоках
*/
/*
PIP - Platform Independent Primitives
Class for simply notify and wait in different threads
Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
Class for simply notify and wait in different threads
Andrey Bychkov work.a.b@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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PITHREADNOTIFIER_H

View File

@@ -1,20 +1,20 @@
/*
PIP - Platform Independent Primitives
PIP - Platform Independent Primitives
Stephan Fomenko
Stephan Fomenko
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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pithreadpoolexecutor.h"
@@ -26,9 +26,9 @@
*/
PIThreadPoolExecutor::PIThreadPoolExecutor(int corePoolSize) : isShutdown_(false) {
PIThreadPoolExecutor::PIThreadPoolExecutor(int corePoolSize): isShutdown_(false) {
for (int i = 0; i < corePoolSize; ++i) {
PIThread * thread = new PIThread([&, i](){
PIThread * thread = new PIThread([&, i]() {
auto runnable = taskQueue.poll(100, std::function<void()>());
if (runnable) {
runnable();
@@ -54,13 +54,15 @@ bool PIThreadPoolExecutor::awaitTermination(int timeoutMs) {
void PIThreadPoolExecutor::shutdownNow() {
isShutdown_ = true;
for (size_t i = 0; i < threadPool.size(); ++i) threadPool[i]->stop();
for (size_t i = 0; i < threadPool.size(); ++i)
threadPool[i]->stop();
}
PIThreadPoolExecutor::~PIThreadPoolExecutor() {
shutdownNow();
while (threadPool.size() > 0) delete threadPool.take_back();
while (threadPool.size() > 0)
delete threadPool.take_back();
}

View File

@@ -1,20 +1,20 @@
/*
PIP - Platform Independent Primitives
PIP - Platform Independent Primitives
Stephan Fomenko
Stephan Fomenko
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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PITHREADPOOLEXECUTOR_H

View File

@@ -1,23 +1,24 @@
/*
PIP - Platform Independent Primitives
Thread pool loop
Ivan Pelipenko peri4ko@yandex.ru
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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pithreadpoolloop.h"
#include "pisysteminfo.h"
#include "pithread.h"
@@ -102,27 +103,25 @@
PIThreadPoolLoop::PIThreadPoolLoop(int thread_cnt) {
if (thread_cnt <= 0)
thread_cnt = piMaxi(1, PISystemInfo::instance()->processorsCount);
piForTimes (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";
// piCout << "PIThreadPoolLoop" << proc_cnt << "threads";
}
PIThreadPoolLoop::~PIThreadPoolLoop() {
for (auto * t: threads) {
t->stop();
if (!t->waitForFinish(100))
t->terminate();
if (!t->waitForFinish(100)) t->terminate();
delete t;
}
}
void PIThreadPoolLoop::setFunction(std::function<void (int)> f) {
void PIThreadPoolLoop::setFunction(std::function<void(int)> f) {
func = f;
}
@@ -131,7 +130,7 @@ 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](){
t->start([this, end, t]() {
while (1) {
int cc = counter.fetch_add(1);
if (cc >= end) {
@@ -150,7 +149,7 @@ void PIThreadPoolLoop::exec(int index_start, int index_count) {
}
void PIThreadPoolLoop::exec(int index_start, int index_count, std::function<void (int)> f) {
void PIThreadPoolLoop::exec(int index_start, int index_count, std::function<void(int)> f) {
setFunction(f);
exec(index_start, index_count);
}

View File

@@ -5,22 +5,22 @@
* \~russian Пул потоков
*/
/*
PIP - Platform Independent Primitives
Thread pool loop
Ivan Pelipenko peri4ko@yandex.ru
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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PITHREADPOOLLOOP_H
@@ -32,7 +32,6 @@ 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
@@ -43,8 +42,10 @@ public:
virtual ~PIThreadPoolLoop();
//! \~english Set threads function to [lambda expression](https://en.cppreference.com/w/cpp/language/lambda) "f" with format [ ](int){ ... }
//! \~russian Устанавливает функцию потоков на [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda) "f" в формате [ ](int){ ... }
//! \~english Set threads function to [lambda expression](https://en.cppreference.com/w/cpp/language/lambda) "f" with format [ ](int){
//! ... }
//! \~russian Устанавливает функцию потоков на [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda) "f" в формате [
//! ](int){ ... }
void setFunction(std::function<void(int)> f);
//! \~english Wait for all threads stop
@@ -80,10 +81,9 @@ public:
void exec(int index_start, int index_count, std::function<void(int)> f);
private:
PIVector<PIThread * > threads;
PIVector<PIThread *> threads;
std::function<void(int)> func;
std::atomic_int counter;
};

View File

@@ -1,25 +1,26 @@
/*
PIP - Platform Independent Primitives
Timer
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Timer
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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pitimer.h"
#include "piincludes_p.h"
#include "piconditionvar.h"
#include "piincludes_p.h"
#ifdef PIP_TIMER_RT
# include <csignal>
#endif
@@ -50,7 +51,8 @@
//! \~russian \section PITimer_sec1 Варианты уведомления
//! \~english
//! Notify variants:
//! * "slot" - static function with format void func(void * data, int delimiter) or [lambda expression](https://en.cppreference.com/w/cpp/language/lambda);
//! * "slot" - static function with format void func(void * data, int delimiter) or [lambda
//! expression](https://en.cppreference.com/w/cpp/language/lambda);
//! * event - \a tickEvent();
//! * virtual function - \a tick().
//!
@@ -59,7 +61,8 @@
//! All these variants are equivalent, use most applicable.
//! \~russian
//! Варианты уведомления:
//! * "slot" - статический метод в формате void func(void * data, int delimiter) или [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda);
//! * "slot" - статический метод в формате void func(void * data, int delimiter) или
//! [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda);
//! * event - \a tickEvent();
//! * виртуальный метод - \a tick().
//!
@@ -116,18 +119,18 @@
_PITimerBase::_PITimerBase() {
interval_ = 1000;
interval_ = 1000;
deferred_delay = 0.;
running_ = deferred_ = deferred_mode = false;
tfunc = 0;
parent = 0;
tfunc = 0;
parent = 0;
}
void _PITimerBase::setInterval(double i) {
interval_ = i;
if (isRunning()) {
//piCout << "change interval runtime";
// piCout << "change interval runtime";
stop();
start();
}
@@ -138,7 +141,7 @@ bool _PITimerBase::start(double interval_ms) {
if (isRunning()) stop();
deferred_ = false;
setInterval(interval_ms);
//piCout << "_PITimerBase::startTimer"<<interval_ms<<"...";
// piCout << "_PITimerBase::startTimer"<<interval_ms<<"...";
running_ = startTimer(interval_ms);
return running_;
}
@@ -146,8 +149,8 @@ bool _PITimerBase::start(double interval_ms) {
void _PITimerBase::startDeferred(double interval_ms, PIDateTime start_datetime) {
if (isRunning()) stop();
deferred_ = true;
deferred_mode = true;
deferred_ = true;
deferred_mode = true;
deferred_datetime = start_datetime;
setInterval(interval_ms);
running_ = startTimer(interval_ms);
@@ -156,8 +159,8 @@ void _PITimerBase::startDeferred(double interval_ms, PIDateTime start_datetime)
void _PITimerBase::startDeferred(double interval_ms, double delay_ms) {
if (isRunning()) stop();
deferred_ = true;
deferred_mode = false;
deferred_ = true;
deferred_mode = false;
deferred_delay = delay_ms;
setInterval(interval_ms);
running_ = startTimer(interval_ms);
@@ -165,28 +168,28 @@ void _PITimerBase::startDeferred(double interval_ms, double delay_ms) {
bool _PITimerBase::stop() {
//piCout << GetCurrentThreadId() << "_PITimerBase::stop" << wait << isRunning();
// piCout << GetCurrentThreadId() << "_PITimerBase::stop" << wait << isRunning();
if (!isRunning()) return true;
//piCout << "_PITimerBase::stopTimer ...";
// piCout << "_PITimerBase::stopTimer ...";
running_ = !stopTimer();
return !running_;
}
class _PITimerImp_Thread: public _PITimerBase {
public:
_PITimerImp_Thread();
virtual ~_PITimerImp_Thread() {stop();}
virtual ~_PITimerImp_Thread() { stop(); }
protected:
void prepareStart(double interval_ms);
bool threadFunc(); // returns true if repeat is needed
int wait_dt, wait_dd, wait_tick;
private:
bool startTimer(double interval_ms) override;
bool stopTimer() override;
static void threadFuncS(void * d) {((_PITimerImp_Thread*)d)->threadFunc();}
static void threadFuncS(void * d) { ((_PITimerImp_Thread *)d)->threadFunc(); }
void adjustTimes();
bool smallWait(int ms);
@@ -202,7 +205,9 @@ class _PITimerImp_RT: public _PITimerBase {
public:
_PITimerImp_RT();
virtual ~_PITimerImp_RT();
protected:
private:
bool startTimer(double interval_ms) override;
bool stopTimer() override;
@@ -216,7 +221,8 @@ private:
class _PITimerImp_Pool: public _PITimerImp_Thread {
public:
_PITimerImp_Pool();
virtual ~_PITimerImp_Pool() {stop();}
virtual ~_PITimerImp_Pool() { stop(); }
private:
class Pool: public PIThread {
public:
@@ -224,7 +230,8 @@ private:
void add(_PITimerImp_Pool * t);
void remove(_PITimerImp_Pool * t);
void run() override;
PIVector<_PITimerImp_Pool * > timers, to_remove;
PIVector<_PITimerImp_Pool *> timers, to_remove;
private:
explicit Pool();
virtual ~Pool();
@@ -234,15 +241,13 @@ private:
};
_PITimerImp_Thread::_PITimerImp_Thread() {
thread_.setName("__S__PITimerImp_Thread::thread");
wait_dt = 1000;
wait_dd = 2000;
wait_dt = 1000;
wait_dd = 2000;
wait_tick = 1000;
//piCout << "_PITimerImp_Thread" << this << ", thread& =" << &thread_;
//piCout << "new _PITimerImp_Thread";
// piCout << "_PITimerImp_Thread" << this << ", thread& =" << &thread_;
// piCout << "new _PITimerImp_Thread";
}
@@ -256,8 +261,7 @@ void _PITimerImp_Thread::prepareStart(double interval_ms) {
st_odt = st_inc * 5;
if (st_odt.toSeconds() < 1.) st_odt = PISystemTime::fromSeconds(1.);
if (deferred_) {
if (!deferred_mode)
st_time = PISystemTime::current(true) + PISystemTime::fromMilliseconds(deferred_delay);
if (!deferred_mode) st_time = PISystemTime::current(true) + PISystemTime::fromMilliseconds(deferred_delay);
st_time -= st_inc;
} else
st_time = PISystemTime::current(true) + st_inc;
@@ -275,10 +279,10 @@ bool _PITimerImp_Thread::stopTimer() {
thread_.stop();
event.notifyAll();
thread_.waitForFinish();
// if (wait)
// if (!thread_.waitForFinish(10))
// if (thread_.isRunning())
// thread_.terminate();
// if (wait)
// if (!thread_.waitForFinish(10))
// if (thread_.isRunning())
// thread_.terminate();
return true;
}
@@ -300,19 +304,18 @@ bool _PITimerImp_Thread::threadFunc() {
} else {
if (!smallWait(dwt.toMilliseconds())) return false;
deferred_ = false;
st_time = PISystemTime::current(true);
st_time = PISystemTime::current(true);
}
} else {
if (dwt.toMilliseconds() > 0.1)
return false;
if (dwt.toMilliseconds() > 0.1) return false;
}
}
st_wait = st_time - PISystemTime::current(true);
//piCout << "wait" << this << st_wait;
// piCout << "wait" << this << st_wait;
if (st_wait.abs() > st_odt || st_wait.seconds <= -5) {
//piCout << &thread_ << "adjust" << "...";
// piCout << &thread_ << "adjust" << "...";
adjustTimes();
//piCout << &thread_ << "adjust" << "ok";
// piCout << &thread_ << "adjust" << "ok";
return true;
}
if (wait_tick > 0) {
@@ -320,21 +323,20 @@ bool _PITimerImp_Thread::threadFunc() {
smallWait(wait_tick);
return false;
} else {
//piCout << &thread_ << "sleep for" << st_wait;
// piCout << &thread_ << "sleep for" << st_wait;
if (!smallWait(st_wait.toMilliseconds())) return false;
}
} else {
if (st_wait.toMilliseconds() > 0.1)
return false;
if (st_wait.toMilliseconds() > 0.1) return false;
}
st_time += st_inc;
if (!parent->isPIObject()) {
piCout << "Achtung! PITimer \"parent\" is not PIObject!";
return false;
}
//piCout << &thread_ << "tfunc" << "...";
// piCout << &thread_ << "tfunc" << "...";
tfunc(parent);
//piCout << &thread_ << "tfunc" << "ok";
// piCout << &thread_ << "tfunc" << "ok";
return true;
}
@@ -373,11 +375,11 @@ bool _PITimerImp_Thread::smallWait(int ms) {
}
#ifdef PIP_TIMER_RT
void threadFuncS(sigval sv) {((_PITimerImp_RT * )sv.sival_ptr)->tfunc(((_PITimerImp_RT * )sv.sival_ptr)->parent);}
void threadFuncS(sigval sv) {
((_PITimerImp_RT *)sv.sival_ptr)->tfunc(((_PITimerImp_RT *)sv.sival_ptr)->parent);
}
struct _PITimerImp_RT_Private_ {
itimerspec spec;
@@ -386,14 +388,14 @@ struct _PITimerImp_RT_Private_ {
};
_PITimerImp_RT::_PITimerImp_RT() {
//piCout << "new _PITimerImp_RT";
priv = new _PITimerImp_RT_Private_();
// piCout << "new _PITimerImp_RT";
priv = new _PITimerImp_RT_Private_();
priv->tt = 0;
ti = -1;
ti = -1;
memset(&(priv->se), 0, sizeof(priv->se));
priv->se.sigev_notify = SIGEV_THREAD;
priv->se.sigev_value.sival_ptr = this;
priv->se.sigev_notify_function = threadFuncS;
priv->se.sigev_notify = SIGEV_THREAD;
priv->se.sigev_value.sival_ptr = this;
priv->se.sigev_notify_function = threadFuncS;
priv->se.sigev_notify_attributes = 0;
}
@@ -407,22 +409,22 @@ _PITimerImp_RT::~_PITimerImp_RT() {
bool _PITimerImp_RT::startTimer(double interval_ms) {
int flags(0);
priv->spec.it_interval.tv_nsec = ((int)(interval_ms * 1000) % 1000000) * 1000;
priv->spec.it_interval.tv_sec = (time_t)(interval_ms / 1000);
priv->spec.it_interval.tv_sec = (time_t)(interval_ms / 1000);
if (deferred_) {
if (deferred_mode) {
PISystemTime dtm = deferred_datetime.toSystemTime();
PISystemTime dtm = deferred_datetime.toSystemTime();
priv->spec.it_value.tv_nsec = dtm.nanoseconds;
priv->spec.it_value.tv_sec = dtm.seconds;
flags = TIMER_ABSTIME;
priv->spec.it_value.tv_sec = dtm.seconds;
flags = TIMER_ABSTIME;
} else {
priv->spec.it_value.tv_nsec = ((int)(deferred_delay * 1000) % 1000000) * 1000;
priv->spec.it_value.tv_sec = (time_t)(deferred_delay / 1000);
priv->spec.it_value.tv_sec = (time_t)(deferred_delay / 1000);
}
} else {
priv->spec.it_value = priv->spec.it_interval;
}
ti = timer_create(CLOCK_REALTIME, &(priv->se), &(priv->tt));
//cout << "***create timer " << msecs << " msecs\n";
// cout << "***create timer " << msecs << " msecs\n";
if (ti == -1) {
piCout << "Can`t create RT timer for " << interval_ms << " msecs: " << errorString();
return false;
@@ -435,7 +437,7 @@ bool _PITimerImp_RT::startTimer(double interval_ms) {
bool _PITimerImp_RT::stopTimer() {
if (ti < 0) return true;
timer_delete(priv->tt);
ti = -1;
ti = -1;
priv->tt = 0;
return true;
}
@@ -443,11 +445,9 @@ bool _PITimerImp_RT::stopTimer() {
#endif
_PITimerImp_Pool::_PITimerImp_Pool(): _PITimerImp_Thread() {
wait_dt = wait_dd = wait_tick = 0;
//piCout << "new _PITimerImp_Pool";
// piCout << "new _PITimerImp_Pool";
}
@@ -456,7 +456,7 @@ _PITimerImp_Pool::Pool::Pool(): PIThread() {
needLockRun(true);
#ifndef FREERTOS
timers.reserve(64);
start(PIP_MIN_MSLEEP*5);
start(PIP_MIN_MSLEEP * 5);
#else
start(PIP_MIN_MSLEEP);
#endif
@@ -465,8 +465,7 @@ _PITimerImp_Pool::Pool::Pool(): PIThread() {
_PITimerImp_Pool::Pool::~Pool() {
stop();
if (!waitForFinish(500))
terminate();
if (!waitForFinish(500)) terminate();
unlock();
timers.clear();
}
@@ -479,32 +478,31 @@ _PITimerImp_Pool::Pool * _PITimerImp_Pool::Pool::instance() {
void _PITimerImp_Pool::Pool::add(_PITimerImp_Pool * t) {
//piCout << "add ...";
// piCout << "add ...";
lock();
to_remove.removeAll(t);
if (!timers.contains(t))
timers << t;
if (!timers.contains(t)) timers << t;
unlock();
//piCout << "add done";
// piCout << "add done";
}
void _PITimerImp_Pool::Pool::remove(_PITimerImp_Pool * t) {
//piCout << "remove ...";
// piCout << "remove ...";
lock();
to_remove << t;
unlock();
//piCout << "remove done";
// piCout << "remove done";
}
void _PITimerImp_Pool::Pool::run() {
if (!to_remove.isEmpty()) {
piForeach (_PITimerImp_Pool * t, to_remove)
piForeach(_PITimerImp_Pool * t, to_remove)
timers.removeAll(t);
to_remove.clear();
}
piForeach (_PITimerImp_Pool * t, timers)
piForeach(_PITimerImp_Pool * t, timers)
t->threadFunc();
}
@@ -522,9 +520,6 @@ bool _PITimerImp_Pool::stopTimer() {
}
PITimer::PITimer(): PIObject() {
#ifdef FREERTOS
imp_mode = PITimer::Thread;
@@ -544,23 +539,23 @@ PITimer::PITimer(PITimer::TimerImplementation ti): PIObject() {
PITimer::PITimer(TimerEvent slot, void * data, PITimer::TimerImplementation ti): PIObject() {
imp_mode = ti;
initFirst();
data_t = data;
data_t = data;
ret_func = slot;
}
PITimer::PITimer(std::function<void ()> slot, PITimer::TimerImplementation ti) {
PITimer::PITimer(std::function<void()> slot, PITimer::TimerImplementation ti) {
imp_mode = ti;
initFirst();
ret_func = [slot](void *, int){slot();};
ret_func = [slot](void *, int) { slot(); };
}
PITimer::PITimer(std::function<void (void *)> slot, void * data, PITimer::TimerImplementation ti) {
PITimer::PITimer(std::function<void(void *)> slot, void * data, PITimer::TimerImplementation ti) {
imp_mode = ti;
initFirst();
data_t = data;
ret_func = [slot](void *d, int){slot(d);};
data_t = data;
ret_func = [slot](void * d, int) { slot(d); };
}
@@ -595,11 +590,11 @@ bool PITimer::isStopped() const {
void PITimer::initFirst() {
lockRun = false;
lockRun = false;
callEvents = true;
data_t = 0;
ret_func = 0;
imp = 0;
data_t = 0;
ret_func = 0;
imp = 0;
setProperty("interval", 0.);
}
@@ -619,15 +614,15 @@ void PITimer::init() const {
default: piCout << "Fatal: invalid implementation() of" << this << "!"; assert(0);
}
if (!imp) return;
//piCout << this << "init" << imp;
imp->tfunc = tickImpS;
imp->parent = const_cast<PITimer*>(this);
// piCout << this << "init" << imp;
imp->tfunc = tickImpS;
imp->parent = const_cast<PITimer *>(this);
}
void PITimer::destroy() {
if (!imp) return;
//piCout << this << "destroy" << imp;
// piCout << this << "destroy" << imp;
imp->stop();
delete imp;
imp = 0;
@@ -641,11 +636,13 @@ void PITimer::tickImp() {
tick(data_t, 1);
tickEvent(data_t, 1);
if (callEvents) maybeCallQueuedEvents();
piForeach (Delimiter & i, delims) {
piForeach(Delimiter & i, delims) {
if (i.delim > ++(i.tick)) continue;
i.tick = 0;
if (i.slot) i.slot(data_t, i.delim);
else if (ret_func) ret_func(data_t, i.delim);
if (i.slot)
i.slot(data_t, i.delim);
else if (ret_func)
ret_func(data_t, i.delim);
tick(data_t, i.delim);
tickEvent(data_t, i.delim);
}
@@ -655,14 +652,14 @@ void PITimer::tickImp() {
bool PITimer::start() {
init();
//piCout << this << "start" << imp;
// piCout << this << "start" << imp;
return imp->start();
}
bool PITimer::start(double interval_ms_d) {
init();
//piCout << this << "start" << imp << interval_ms_d;
// piCout << this << "start" << imp << interval_ms_d;
setProperty("interval", interval_ms_d);
return imp->start(interval_ms_d);
}
@@ -725,7 +722,6 @@ bool PITimer::restart() {
bool PITimer::stop() {
init();
//piCout << this << "stop" << imp << wait;
// piCout << this << "stop" << imp << wait;
return imp->stop();
}

View File

@@ -5,22 +5,22 @@
* \~russian Таймер
*/
/*
PIP - Platform Independent Primitives
Timer
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Timer
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 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.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PITIMER_H
@@ -87,19 +87,19 @@ public:
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
};