Merge pull request 'condvar_use' (#82) from condvar_use into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/82
This commit was merged in pull request #82.
This commit is contained in:
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
|
|||||||
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
|
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
|
||||||
project(pip)
|
project(pip)
|
||||||
set(pip_MAJOR 2)
|
set(pip_MAJOR 2)
|
||||||
set(pip_MINOR 32)
|
set(pip_MINOR 33)
|
||||||
set(pip_REVISION 0)
|
set(pip_REVISION 0)
|
||||||
set(pip_SUFFIX )
|
set(pip_SUFFIX )
|
||||||
set(pip_COMPANY SHS)
|
set(pip_COMPANY SHS)
|
||||||
|
|||||||
@@ -285,10 +285,10 @@
|
|||||||
#define FOREVER for (;;)
|
#define FOREVER for (;;)
|
||||||
|
|
||||||
//! Macro used for infinite wait
|
//! Macro used for infinite wait
|
||||||
#define FOREVER_WAIT FOREVER msleep(PIP_MIN_MSLEEP);
|
#define FOREVER_WAIT FOREVER piMinSleep;
|
||||||
|
|
||||||
//! Macro used for infinite wait
|
//! Macro used for infinite wait
|
||||||
#define WAIT_FOREVER FOREVER msleep(PIP_MIN_MSLEEP);
|
#define WAIT_FOREVER FOREVER piMinSleep;
|
||||||
|
|
||||||
|
|
||||||
//! global variable enabling output to piCout, default is true
|
//! global variable enabling output to piCout, default is true
|
||||||
|
|||||||
@@ -698,28 +698,30 @@ bool PIObject::Connection::disconnect() {
|
|||||||
PRIVATE_DEFINITION_START(PIObject::Deleter)
|
PRIVATE_DEFINITION_START(PIObject::Deleter)
|
||||||
PIThread thread;
|
PIThread thread;
|
||||||
PIConditionVariable cond_var;
|
PIConditionVariable cond_var;
|
||||||
PIMutex cond_mutex, queue_mutex;
|
|
||||||
PIVector<PIObject*> obj_queue;
|
PIVector<PIObject*> obj_queue;
|
||||||
PRIVATE_DEFINITION_END(PIObject::Deleter)
|
PRIVATE_DEFINITION_END(PIObject::Deleter)
|
||||||
|
|
||||||
|
|
||||||
PIObject::Deleter::Deleter() {
|
PIObject::Deleter::Deleter() {
|
||||||
//piCout << "Deleter start ...";
|
//piCout << "Deleter start ...";
|
||||||
stopping = started = posted = false;
|
PRIVATE->thread.setSlot([this](){
|
||||||
CONNECTL(&(PRIVATE->thread), started, [this](){proc();});
|
PIVector<PIObject*> oq;
|
||||||
PRIVATE->thread.startOnce();
|
PRIVATE->thread.lock();
|
||||||
while (!started) piMSleep(1);
|
while(PRIVATE->obj_queue.isEmpty()) PRIVATE->cond_var.wait(PRIVATE->thread.mutex());
|
||||||
|
oq.swap(PRIVATE->obj_queue);
|
||||||
|
PRIVATE->thread.unlock();
|
||||||
|
for (PIObject * o : oq) deleteObject(o);
|
||||||
|
});
|
||||||
|
PRIVATE->thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIObject::Deleter::~Deleter() {
|
PIObject::Deleter::~Deleter() {
|
||||||
//piCout << "~Deleter ...";
|
//piCout << "~Deleter ...";
|
||||||
stopping = true;
|
PRIVATE->thread.stop();
|
||||||
PRIVATE->cond_var.notifyAll();
|
PRIVATE->cond_var.notifyAll();
|
||||||
#ifndef WINDOWS
|
PRIVATE->thread.waitForFinish();
|
||||||
while (PRIVATE->thread.isRunning()) piMSleep(1);
|
for (PIObject * o : PRIVATE->obj_queue) deleteObject(o);
|
||||||
#endif
|
|
||||||
deleteAll();
|
|
||||||
//piCout << "~Deleter ok";
|
//piCout << "~Deleter ok";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -733,56 +735,23 @@ PIObject::Deleter * PIObject::Deleter::instance() {
|
|||||||
void PIObject::Deleter::post(PIObject * o) {
|
void PIObject::Deleter::post(PIObject * o) {
|
||||||
if (!o->isPIObject()) return;
|
if (!o->isPIObject()) return;
|
||||||
//piCout << "[Deleter] post" << o << "...";
|
//piCout << "[Deleter] post" << o << "...";
|
||||||
PRIVATE->queue_mutex.lock();
|
PRIVATE->thread.lock();
|
||||||
if (!PRIVATE->obj_queue.contains(o))
|
if (!PRIVATE->obj_queue.contains(o)) {
|
||||||
PRIVATE->obj_queue << o;
|
PRIVATE->obj_queue << o;
|
||||||
PRIVATE->queue_mutex.unlock();
|
|
||||||
PRIVATE->cond_var.notifyAll();
|
PRIVATE->cond_var.notifyAll();
|
||||||
posted = true;
|
}
|
||||||
|
PRIVATE->thread.unlock();
|
||||||
//piCout << "[Deleter] post" << o << "done";
|
//piCout << "[Deleter] post" << o << "done";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIObject::Deleter::proc() {
|
|
||||||
//piCout << "[Deleter] proc start";
|
|
||||||
while (!stopping) {
|
|
||||||
//piMSleep(1);
|
|
||||||
//piCout << "[Deleter] proc wait ...";
|
|
||||||
if (posted) {
|
|
||||||
posted = false;
|
|
||||||
started = true;
|
|
||||||
} else {
|
|
||||||
PRIVATE->cond_mutex.lock();
|
|
||||||
started = true;
|
|
||||||
PRIVATE->cond_var.wait(PRIVATE->cond_mutex);
|
|
||||||
PRIVATE->cond_mutex.unlock();
|
|
||||||
}
|
|
||||||
//piCout << "[Deleter] proc wait done";
|
|
||||||
deleteAll();
|
|
||||||
}
|
|
||||||
//piCout << "[Deleter] proc end ok";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void PIObject::Deleter::deleteAll() {
|
|
||||||
PIVector<PIObject*> oq;
|
|
||||||
PRIVATE->queue_mutex.lock();
|
|
||||||
oq = PRIVATE->obj_queue;
|
|
||||||
//piCout << "[Deleter] deleteAll" << oq.size_s() << "...";
|
|
||||||
PRIVATE->obj_queue.clear();
|
|
||||||
PRIVATE->queue_mutex.unlock();
|
|
||||||
piForeach (PIObject * o, oq)
|
|
||||||
deleteObject(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void PIObject::Deleter::deleteObject(PIObject * o) {
|
void PIObject::Deleter::deleteObject(PIObject * o) {
|
||||||
//piCout << "[Deleter] delete" << (uintptr_t)o << "...";
|
//piCout << "[Deleter] delete" << (uintptr_t)o << "...";
|
||||||
if (o->isPIObject()) {
|
if (o->isPIObject()) {
|
||||||
//piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic ...";
|
//piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic ...";
|
||||||
while (o->isInEvent()) piMSleep(1);
|
while (o->isInEvent()) piMinSleep();
|
||||||
//piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic done";
|
//piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic done";
|
||||||
if (o->isPIObject()) delete o;
|
delete o;
|
||||||
}
|
}
|
||||||
//piCout << "[Deleter] delete" << (uintptr_t)o << "done";
|
//piCout << "[Deleter] delete" << (uintptr_t)o << "done";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -503,10 +503,7 @@ private:
|
|||||||
static Deleter * instance();
|
static Deleter * instance();
|
||||||
void post(PIObject * o);
|
void post(PIObject * o);
|
||||||
private:
|
private:
|
||||||
void proc();
|
|
||||||
void deleteAll();
|
|
||||||
void deleteObject(PIObject * o);
|
void deleteObject(PIObject * o);
|
||||||
std::atomic_bool stopping, started, posted;
|
|
||||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -469,13 +469,3 @@ PICout operator <<(PICout s, const PIDateTime & v) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef WINDOWS
|
|
||||||
void msleep(int msecs) {Sleep(msecs);}
|
|
||||||
#else
|
|
||||||
# ifdef FREERTOS
|
|
||||||
void msleep(int msecs) {vTaskDelay(msecs / portTICK_PERIOD_MS);}
|
|
||||||
# else
|
|
||||||
void msleep(int msecs) {usleep(msecs * 1000);}
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -29,8 +29,6 @@
|
|||||||
#ifdef QNX
|
#ifdef QNX
|
||||||
# include <time.h>
|
# include <time.h>
|
||||||
#endif
|
#endif
|
||||||
//! @brief Sleep for "msecs" milliseconds
|
|
||||||
PIP_EXPORT void msleep(int msecs);
|
|
||||||
|
|
||||||
/*! @brief Precise sleep for "usecs" microseconds
|
/*! @brief Precise sleep for "usecs" microseconds
|
||||||
* \details This function consider \c "usleep" offset
|
* \details This function consider \c "usleep" offset
|
||||||
@@ -48,6 +46,8 @@ inline void piMSleep(double msecs) {piUSleep(int(msecs * 1000.));} // on !Window
|
|||||||
* \details This function exec \a piUSleep (msecs * 1000000). */
|
* \details This function exec \a piUSleep (msecs * 1000000). */
|
||||||
inline void piSleep(double secs) {piUSleep(int(secs * 1000000.));} // on !Windows consider constant "usleep" offset
|
inline void piSleep(double secs) {piUSleep(int(secs * 1000000.));} // on !Windows consider constant "usleep" offset
|
||||||
|
|
||||||
|
//! Shortest available on current system sleep
|
||||||
|
inline void piMinSleep() {piMSleep(PIP_MIN_MSLEEP);}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -686,7 +686,7 @@ int PIEthernet::readDevice(void * read_to, int max_size) {
|
|||||||
s = accept(sock, (sockaddr * )&client_addr, &slen);
|
s = accept(sock, (sockaddr * )&client_addr, &slen);
|
||||||
if (s == -1) {
|
if (s == -1) {
|
||||||
//piCoutObj << "Can`t accept new connection, " << ethErrorString();
|
//piCoutObj << "Can`t accept new connection, " << ethErrorString();
|
||||||
msleep(PIP_MIN_MSLEEP);
|
piMinSleep();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
rs = ethRecv(s, read_to, max_size);
|
rs = ethRecv(s, read_to, max_size);
|
||||||
@@ -788,7 +788,7 @@ int PIEthernet::writeDevice(const void * data, int max_size) {
|
|||||||
//piCoutObj << "connect SingleTCP" << ip_s << ":" << port_s << "...";
|
//piCoutObj << "connect SingleTCP" << ip_s << ":" << port_s << "...";
|
||||||
if (::connect(sock, (sockaddr * )&PRIVATE->addr_, sizeof(PRIVATE->addr_)) != 0) {
|
if (::connect(sock, (sockaddr * )&PRIVATE->addr_, sizeof(PRIVATE->addr_)) != 0) {
|
||||||
//piCoutObj << "Can`t connect to " << ip_s << ":" << port_s << ", " << ethErrorString();
|
//piCoutObj << "Can`t connect to " << ip_s << ":" << port_s << ", " << ethErrorString();
|
||||||
msleep(PIP_MIN_MSLEEP);
|
piMinSleep();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
//piCoutObj << "ok, write SingleTCP" << int(data) << max_size << "bytes ...";
|
//piCoutObj << "ok, write SingleTCP" << int(data) << max_size << "bytes ...";
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ void PIIODevice::write_func() {
|
|||||||
int ret = write(item.first);
|
int ret = write(item.first);
|
||||||
threadedWriteEvent(item.second, ret);
|
threadedWriteEvent(item.second, ret);
|
||||||
}
|
}
|
||||||
msleep(PIP_MIN_MSLEEP);
|
piMinSleep();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,7 +338,7 @@ PIByteArray PIIODevice::readForTime(double timeout_ms) {
|
|||||||
tm.reset();
|
tm.reset();
|
||||||
while (tm.elapsed_m() < timeout_ms) {
|
while (tm.elapsed_m() < timeout_ms) {
|
||||||
ret = read(td, threaded_read_buffer_size);
|
ret = read(td, threaded_read_buffer_size);
|
||||||
if (ret <= 0) msleep(PIP_MIN_MSLEEP);
|
if (ret <= 0) piMinSleep();
|
||||||
else str.append(td, ret);
|
else str.append(td, ret);
|
||||||
}
|
}
|
||||||
delete[] td;
|
delete[] td;
|
||||||
|
|||||||
@@ -434,7 +434,7 @@ bool PISerial::read(void * data, int size, double timeout_ms) {
|
|||||||
while (all < size && tm_.elapsed_m() < timeout_ms) {
|
while (all < size && tm_.elapsed_m() < timeout_ms) {
|
||||||
ret = readDevice(&((uchar * )data)[all], size - all);
|
ret = readDevice(&((uchar * )data)[all], size - all);
|
||||||
if (ret > 0) all += ret;
|
if (ret > 0) all += ret;
|
||||||
else msleep(PIP_MIN_MSLEEP);
|
else piMinSleep();
|
||||||
}
|
}
|
||||||
setOption(BlockingRead, br);
|
setOption(BlockingRead, br);
|
||||||
received(data, all);
|
received(data, all);
|
||||||
@@ -473,13 +473,13 @@ PIString PISerial::read(int size, double timeout_ms) {
|
|||||||
if (size <= 0) {
|
if (size <= 0) {
|
||||||
while (tm_.elapsed_m() < timeout_ms) {
|
while (tm_.elapsed_m() < timeout_ms) {
|
||||||
ret = readDevice(td, 1024);
|
ret = readDevice(td, 1024);
|
||||||
if (ret <= 0) msleep(PIP_MIN_MSLEEP);
|
if (ret <= 0) piMinSleep();
|
||||||
else str << PIString((char*)td, ret);
|
else str << PIString((char*)td, ret);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (all < size && tm_.elapsed_m() < timeout_ms) {
|
while (all < size && tm_.elapsed_m() < timeout_ms) {
|
||||||
ret = readDevice(td, size - all);
|
ret = readDevice(td, size - all);
|
||||||
if (ret <= 0) msleep(PIP_MIN_MSLEEP);
|
if (ret <= 0) piMinSleep();
|
||||||
else {
|
else {
|
||||||
str << PIString((char*)td, ret);
|
str << PIString((char*)td, ret);
|
||||||
all += ret;
|
all += ret;
|
||||||
@@ -493,7 +493,7 @@ PIString PISerial::read(int size, double timeout_ms) {
|
|||||||
str << PIString((char*)td, all);
|
str << PIString((char*)td, all);
|
||||||
while (all < size) {
|
while (all < size) {
|
||||||
ret = readDevice(td, size - all);
|
ret = readDevice(td, size - all);
|
||||||
if (ret <= 0) msleep(PIP_MIN_MSLEEP);
|
if (ret <= 0) piMinSleep();
|
||||||
else {
|
else {
|
||||||
str << PIString((char*)td, ret);
|
str << PIString((char*)td, ret);
|
||||||
all += ret;
|
all += ret;
|
||||||
@@ -525,13 +525,13 @@ PIByteArray PISerial::readData(int size, double timeout_ms) {
|
|||||||
if (size <= 0) {
|
if (size <= 0) {
|
||||||
while (tm_.elapsed_m() < timeout_ms) {
|
while (tm_.elapsed_m() < timeout_ms) {
|
||||||
ret = readDevice(td, 1024);
|
ret = readDevice(td, 1024);
|
||||||
if (ret <= 0) msleep(PIP_MIN_MSLEEP);
|
if (ret <= 0) piMinSleep();
|
||||||
else str.append(td, ret);
|
else str.append(td, ret);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (all < size && tm_.elapsed_m() < timeout_ms) {
|
while (all < size && tm_.elapsed_m() < timeout_ms) {
|
||||||
ret = readDevice(td, size - all);
|
ret = readDevice(td, size - all);
|
||||||
if (ret <= 0) msleep(PIP_MIN_MSLEEP);
|
if (ret <= 0) piMinSleep();
|
||||||
else {
|
else {
|
||||||
str.append(td, ret);
|
str.append(td, ret);
|
||||||
all += ret;
|
all += ret;
|
||||||
@@ -545,7 +545,7 @@ PIByteArray PISerial::readData(int size, double timeout_ms) {
|
|||||||
str.append(td, all);
|
str.append(td, all);
|
||||||
while (all < size) {
|
while (all < size) {
|
||||||
ret = readDevice(td, size - all);
|
ret = readDevice(td, size - all);
|
||||||
if (ret <= 0) msleep(PIP_MIN_MSLEEP);
|
if (ret <= 0) piMinSleep();
|
||||||
else {
|
else {
|
||||||
str.append(td, ret);
|
str.append(td, ret);
|
||||||
all += ret;
|
all += ret;
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ bool PIBaseTransfer::send_process() {
|
|||||||
if (chk == 0) return finish_send(true);
|
if (chk == 0) return finish_send(true);
|
||||||
if (chk != prev_chk) rtm.reset();
|
if (chk != prev_chk) rtm.reset();
|
||||||
else if (rtm.elapsed_m() < 100) {
|
else if (rtm.elapsed_m() < 100) {
|
||||||
piMSleep(PIP_MIN_MSLEEP);
|
piMinSleep();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (is_pause) {
|
if (is_pause) {
|
||||||
@@ -507,7 +507,7 @@ bool PIBaseTransfer::getStartRequest() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
mutex_session.unlock();
|
mutex_session.unlock();
|
||||||
piMSleep(PIP_MIN_MSLEEP);
|
piMinSleep();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ void PIProcess::exec_() {
|
|||||||
startOnce();
|
startOnce();
|
||||||
//cout << "exec wait" << endl;
|
//cout << "exec wait" << endl;
|
||||||
while (!is_exec)
|
while (!is_exec)
|
||||||
msleep(PIP_MIN_MSLEEP);
|
piMinSleep();
|
||||||
//cout << "exec end" << endl;
|
//cout << "exec end" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ void PIProcess::startProc(bool detached) {
|
|||||||
if (execve(str.data(), a, e) < 0)
|
if (execve(str.data(), a, e) < 0)
|
||||||
piCoutObj << "\"execve" << str << args << "\" error :" << errorString();
|
piCoutObj << "\"execve" << str << args << "\" error :" << errorString();
|
||||||
} else {
|
} else {
|
||||||
msleep(PIP_MIN_MSLEEP);
|
piMinSleep;
|
||||||
//cout << "wait" << endl;
|
//cout << "wait" << endl;
|
||||||
if (!detached) {
|
if (!detached) {
|
||||||
wait(&exit_code);
|
wait(&exit_code);
|
||||||
|
|||||||
@@ -145,9 +145,9 @@ bool PISystemMonitor::startOnSelf(int interval_ms) {
|
|||||||
|
|
||||||
|
|
||||||
PIVector<PISystemMonitor::ThreadStats> PISystemMonitor::threadsStatistic() const {
|
PIVector<PISystemMonitor::ThreadStats> PISystemMonitor::threadsStatistic() const {
|
||||||
mutex_.lock();
|
lock();
|
||||||
PIVector<PISystemMonitor::ThreadStats> ret = cur_ts;
|
PIVector<PISystemMonitor::ThreadStats> ret = cur_ts;
|
||||||
mutex_.unlock();
|
unlock();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,9 +341,9 @@ void PISystemMonitor::run() {
|
|||||||
//piCout << ts_new.cpu_load_user;
|
//piCout << ts_new.cpu_load_user;
|
||||||
}
|
}
|
||||||
last_tm = cur_tm;
|
last_tm = cur_tm;
|
||||||
mutex_.lock();
|
lock();
|
||||||
cur_ts = cur_tm.values();
|
cur_ts = cur_tm.values();
|
||||||
mutex_.unlock();
|
unlock();
|
||||||
tstat.ram_total = totalRAM();
|
tstat.ram_total = totalRAM();
|
||||||
tstat.ram_used = usedRAM();
|
tstat.ram_used = usedRAM();
|
||||||
tstat.ram_free = freeRAM();
|
tstat.ram_free = freeRAM();
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ PRIVATE_DEFINITION_START(PIConditionVariable)
|
|||||||
#else
|
#else
|
||||||
pthread_cond_t nativeHandle;
|
pthread_cond_t nativeHandle;
|
||||||
#endif
|
#endif
|
||||||
bool isDestroying;
|
|
||||||
PRIVATE_DEFINITION_END(PIConditionVariable)
|
PRIVATE_DEFINITION_END(PIConditionVariable)
|
||||||
|
|
||||||
|
|
||||||
@@ -44,7 +43,6 @@ PIConditionVariable::PIConditionVariable() {
|
|||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
InitializeConditionVariable(&PRIVATE->nativeHandle);
|
InitializeConditionVariable(&PRIVATE->nativeHandle);
|
||||||
#else
|
#else
|
||||||
PRIVATE->isDestroying = false;
|
|
||||||
|
|
||||||
pthread_condattr_t condattr;
|
pthread_condattr_t condattr;
|
||||||
pthread_condattr_init(&condattr);
|
pthread_condattr_init(&condattr);
|
||||||
@@ -84,7 +82,6 @@ void PIConditionVariable::wait(PIMutex& lk, const std::function<bool()>& conditi
|
|||||||
#else
|
#else
|
||||||
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
|
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
|
||||||
#endif
|
#endif
|
||||||
if (PRIVATE->isDestroying) return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +97,6 @@ bool PIConditionVariable::waitFor(PIMutex &lk, int timeoutMs) {
|
|||||||
st.toTimespec(&expire_ts);
|
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
|
#endif
|
||||||
if (PRIVATE->isDestroying) return false;
|
|
||||||
return isNotTimeout;
|
return isNotTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +123,6 @@ bool PIConditionVariable::waitFor(PIMutex& lk, int timeoutMs, const std::functio
|
|||||||
bool isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &expire_ts) != 0;
|
bool isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &expire_ts) != 0;
|
||||||
#endif
|
#endif
|
||||||
if (isTimeout) return false;
|
if (isTimeout) return false;
|
||||||
if (PRIVATE->isDestroying) return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ private:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
piMSleep(PIP_MIN_MSLEEP);
|
piMinSleep();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
diag_.received(1);
|
diag_.received(1);
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#include "pithread.h"
|
#include "pithread.h"
|
||||||
#include "piqueue.h"
|
#include "piqueue.h"
|
||||||
|
#include "piconditionvar.h"
|
||||||
|
|
||||||
|
|
||||||
template <typename Tin, typename Tout>
|
template <typename Tin, typename Tout>
|
||||||
class PIPipelineThread : public PIThread
|
class PIPipelineThread : public PIThread
|
||||||
@@ -35,10 +37,10 @@ public:
|
|||||||
cnt = 0;
|
cnt = 0;
|
||||||
max_size = 0;
|
max_size = 0;
|
||||||
wait_next_pipe = false;
|
wait_next_pipe = false;
|
||||||
next_overload = false;
|
|
||||||
}
|
}
|
||||||
~PIPipelineThread() {
|
~PIPipelineThread() {
|
||||||
stop();
|
stop();
|
||||||
|
cv.notifyAll();
|
||||||
if (!waitForFinish(1000)) {
|
if (!waitForFinish(1000)) {
|
||||||
piCoutObj << "terminating self thread";
|
piCoutObj << "terminating self thread";
|
||||||
terminate();
|
terminate();
|
||||||
@@ -46,21 +48,27 @@ public:
|
|||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void connectTo(PIPipelineThread<Tout, T> * next) {
|
void connectTo(PIPipelineThread<Tout, T> * next) {
|
||||||
CONNECT2(void, Tout, bool *, this, calculated, next, enqueue)
|
CONNECT3(void, Tout, bool, bool *, this, calculated, next, enqueue)
|
||||||
}
|
}
|
||||||
EVENT2(calculated, const Tout &, v, bool *, overload)
|
EVENT3(calculated, const Tout &, v, bool, wait, bool *, overload)
|
||||||
void enqueue(const Tin &v) {enqueue(v, 0);}
|
EVENT_HANDLER3(void, enqueue, const Tin &, v, bool, wait, bool *, overload) {
|
||||||
EVENT_HANDLER2(void, enqueue, const Tin &, v, bool *, overload) {
|
|
||||||
mutex.lock();
|
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);
|
||||||
|
mutex_wait.unlock();
|
||||||
|
}
|
||||||
if (max_size == 0 || in.size() < max_size) {
|
if (max_size == 0 || in.size() < max_size) {
|
||||||
in.enqueue(v);
|
in.enqueue(v);
|
||||||
|
cv.notifyAll();
|
||||||
if (overload) *overload = false;
|
if (overload) *overload = false;
|
||||||
} else {
|
} else {
|
||||||
if (overload) *overload = true;
|
if (overload) *overload = true;
|
||||||
}
|
}
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
|
void enqueue(const Tin &v, bool wait = false) {enqueue(v, wait, nullptr);}
|
||||||
const ullong * counterPtr() const {return &cnt;}
|
const ullong * counterPtr() const {return &cnt;}
|
||||||
ullong counter() const {return cnt;}
|
ullong counter() const {return cnt;}
|
||||||
bool isEmpty() {
|
bool isEmpty() {
|
||||||
@@ -79,15 +87,18 @@ public:
|
|||||||
}
|
}
|
||||||
void clear() {
|
void clear() {
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
|
mutex_wait.lock();
|
||||||
in.clear();
|
in.clear();
|
||||||
next_overload = false;
|
cv_wait.notifyAll();
|
||||||
|
mutex_wait.unlock();
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
void stopCalc(int wait_delay = 100) {
|
void stopCalc(int wait_delay = 100) {
|
||||||
if (isRunning()) {
|
if (isRunning()) {
|
||||||
stop();
|
stop();
|
||||||
|
cv.notifyAll();
|
||||||
if (!waitForFinish(wait_delay)) {
|
if (!waitForFinish(wait_delay)) {
|
||||||
mutex_l.unlock();
|
mutex_last.unlock();
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
terminate();
|
terminate();
|
||||||
}
|
}
|
||||||
@@ -95,18 +106,14 @@ public:
|
|||||||
}
|
}
|
||||||
Tout getLast() {
|
Tout getLast() {
|
||||||
Tout ret;
|
Tout ret;
|
||||||
mutex_l.lock();
|
mutex_last.lock();
|
||||||
ret = last;
|
ret = last;
|
||||||
mutex_l.unlock();
|
mutex_last.unlock();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint maxQueSize() {
|
uint maxQueSize() {
|
||||||
uint ret;
|
return max_size;
|
||||||
mutex.lock();
|
|
||||||
ret = max_size;
|
|
||||||
mutex.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMaxQueSize(uint count) {
|
void setMaxQueSize(uint count) {
|
||||||
@@ -127,39 +134,35 @@ protected:
|
|||||||
private:
|
private:
|
||||||
void begin() {cnt = 0;}
|
void begin() {cnt = 0;}
|
||||||
void run() {
|
void run() {
|
||||||
//piCoutObj << "run ...";
|
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
if (in.isEmpty()) {
|
while (in.isEmpty()) {
|
||||||
|
cv.wait(mutex);
|
||||||
|
if (terminating) {
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
piMSleep(10);
|
|
||||||
//piCoutObj << "run in empty";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (next_overload && wait_next_pipe) {
|
}
|
||||||
mutex.unlock();
|
mutex_wait.lock();
|
||||||
//piCoutObj << "wait" << &next_overload;
|
|
||||||
calculated(last, &next_overload);
|
|
||||||
piMSleep(10);
|
|
||||||
} else {
|
|
||||||
Tin t = in.dequeue();
|
Tin t = in.dequeue();
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
|
cv_wait.notifyAll();
|
||||||
|
mutex_wait.unlock();
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
Tout r = calc(t, ok);
|
Tout r = calc(t, ok);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
mutex_l.lock();
|
mutex_last.lock();
|
||||||
last = r;
|
last = r;
|
||||||
mutex_l.unlock();
|
mutex_last.unlock();
|
||||||
cnt++;
|
cnt++;
|
||||||
//piCoutObj << "calc ok" << &next_overload;
|
//piCoutObj << "calc ok";
|
||||||
calculated(r, &next_overload);
|
calculated(r, wait_next_pipe);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//piCoutObj << "run ok";
|
//piCoutObj << "run ok";
|
||||||
}
|
}
|
||||||
PIMutex mutex;
|
PIMutex mutex, mutex_wait;
|
||||||
PIMutex mutex_l;
|
PIConditionVariable cv, cv_wait;
|
||||||
|
PIMutex mutex_last;
|
||||||
bool wait_next_pipe;
|
bool wait_next_pipe;
|
||||||
bool next_overload;
|
|
||||||
ullong cnt;
|
ullong cnt;
|
||||||
PIQueue<Tin> in;
|
PIQueue<Tin> in;
|
||||||
Tout last;
|
Tout last;
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ event started();
|
|||||||
while (isRunning()) {
|
while (isRunning()) {
|
||||||
run();
|
run();
|
||||||
ThreadFunc();
|
ThreadFunc();
|
||||||
msleep(timer_delay);
|
piMSleep(timer_delay);
|
||||||
}
|
}
|
||||||
event stopped();
|
event stopped();
|
||||||
end();
|
end();
|
||||||
@@ -402,7 +402,7 @@ bool PIThread::waitForFinish(int timeout_msecs) {
|
|||||||
if (!running_) return true;
|
if (!running_) return true;
|
||||||
if (timeout_msecs < 0) {
|
if (timeout_msecs < 0) {
|
||||||
while (running_) {
|
while (running_) {
|
||||||
msleep(PIP_MIN_MSLEEP);
|
piMinSleep();
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
if (!isExists(PRIVATE->thread)) {
|
if (!isExists(PRIVATE->thread)) {
|
||||||
unlock();
|
unlock();
|
||||||
@@ -414,7 +414,7 @@ bool PIThread::waitForFinish(int timeout_msecs) {
|
|||||||
}
|
}
|
||||||
tmf_.reset();
|
tmf_.reset();
|
||||||
while (running_ && tmf_.elapsed_m() < timeout_msecs) {
|
while (running_ && tmf_.elapsed_m() < timeout_msecs) {
|
||||||
msleep(PIP_MIN_MSLEEP);
|
piMinSleep();
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
if (!isExists(PRIVATE->thread)) {
|
if (!isExists(PRIVATE->thread)) {
|
||||||
unlock();
|
unlock();
|
||||||
@@ -430,12 +430,12 @@ bool PIThread::waitForStart(int timeout_msecs) {
|
|||||||
if (running_) return true;
|
if (running_) return true;
|
||||||
if (timeout_msecs < 0) {
|
if (timeout_msecs < 0) {
|
||||||
while (!running_)
|
while (!running_)
|
||||||
msleep(PIP_MIN_MSLEEP);
|
piMinSleep();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
tms_.reset();
|
tms_.reset();
|
||||||
while (!running_ && tms_.elapsed_m() < timeout_msecs)
|
while (!running_ && tms_.elapsed_m() < timeout_msecs)
|
||||||
msleep(PIP_MIN_MSLEEP);
|
piMinSleep();
|
||||||
return tms_.elapsed_m() < timeout_msecs;
|
return tms_.elapsed_m() < timeout_msecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,9 +456,9 @@ void PIThread::_beginThread() {
|
|||||||
PIINTROSPECTION_THREAD_START(this);
|
PIINTROSPECTION_THREAD_START(this);
|
||||||
REGISTER_THREAD(this);
|
REGISTER_THREAD(this);
|
||||||
running_ = true;
|
running_ = true;
|
||||||
if (lockRun) mutex_.lock();
|
if (lockRun) thread_mutex.lock();
|
||||||
begin();
|
begin();
|
||||||
if (lockRun) mutex_.unlock();
|
if (lockRun) thread_mutex.unlock();
|
||||||
started();
|
started();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,7 +466,7 @@ void PIThread::_beginThread() {
|
|||||||
void PIThread::_runThread() {
|
void PIThread::_runThread() {
|
||||||
PIINTROSPECTION_THREAD_RUN(this);
|
PIINTROSPECTION_THREAD_RUN(this);
|
||||||
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "...";
|
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "...";
|
||||||
if (lockRun) mutex_.lock();
|
if (lockRun) thread_mutex.lock();
|
||||||
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "ok";
|
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "ok";
|
||||||
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "run" << "...";
|
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "run" << "...";
|
||||||
#ifdef PIP_INTROSPECTION
|
#ifdef PIP_INTROSPECTION
|
||||||
@@ -482,7 +482,7 @@ void PIThread::_runThread() {
|
|||||||
if (ret_func != 0) ret_func(data_);
|
if (ret_func != 0) ret_func(data_);
|
||||||
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "ret_func" << "ok";
|
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "ret_func" << "ok";
|
||||||
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "unlock" << "...";
|
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "unlock" << "...";
|
||||||
if (lockRun) mutex_.unlock();
|
if (lockRun) thread_mutex.unlock();
|
||||||
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "unlock" << "ok";
|
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "unlock" << "ok";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -491,11 +491,11 @@ void PIThread::_endThread() {
|
|||||||
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "...";
|
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "...";
|
||||||
stopped();
|
stopped();
|
||||||
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
|
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
|
||||||
if (lockRun) mutex_.lock();
|
if (lockRun) thread_mutex.lock();
|
||||||
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "end" << "...";
|
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "end" << "...";
|
||||||
end();
|
end();
|
||||||
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
|
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
|
||||||
if (lockRun) mutex_.unlock();
|
if (lockRun) thread_mutex.unlock();
|
||||||
terminating = running_ = false;
|
terminating = running_ = false;
|
||||||
tid_ = -1;
|
tid_ = -1;
|
||||||
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "exit";
|
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "exit";
|
||||||
|
|||||||
@@ -131,11 +131,15 @@ public:
|
|||||||
|
|
||||||
//! @brief Set necessity of lock every \a run with internal mutex
|
//! @brief Set necessity of lock every \a run with internal mutex
|
||||||
void needLockRun(bool need) {lockRun = need;}
|
void needLockRun(bool need) {lockRun = need;}
|
||||||
EVENT_HANDLER0(void, lock) {mutex_.lock();}
|
|
||||||
EVENT_HANDLER0(void, unlock) {mutex_.unlock();}
|
//! @brief Lock internal mutex
|
||||||
|
EVENT_HANDLER0(void, lock) const {thread_mutex.lock();}
|
||||||
|
|
||||||
|
//! @brief Unlock internal mutex
|
||||||
|
EVENT_HANDLER0(void, unlock) const {thread_mutex.unlock();}
|
||||||
|
|
||||||
//! @brief Returns internal mutex
|
//! @brief Returns internal mutex
|
||||||
PIMutex & mutex() {return mutex_;}
|
PIMutex & mutex() const {return thread_mutex;}
|
||||||
|
|
||||||
//! @brief Returns thread ID
|
//! @brief Returns thread ID
|
||||||
llong tid() const {return tid_;}
|
llong tid() const {return tid_;}
|
||||||
@@ -239,7 +243,7 @@ protected:
|
|||||||
int delay_, policy_;
|
int delay_, policy_;
|
||||||
llong tid_;
|
llong tid_;
|
||||||
void * data_;
|
void * data_;
|
||||||
mutable PIMutex mutex_;
|
mutable PIMutex thread_mutex;
|
||||||
PITimeMeasurer tmf_, tms_, tmr_;
|
PITimeMeasurer tmf_, tms_, tmr_;
|
||||||
PIThread::Priority priority_;
|
PIThread::Priority priority_;
|
||||||
ThreadFunc ret_func;
|
ThreadFunc ret_func;
|
||||||
|
|||||||
@@ -29,5 +29,6 @@
|
|||||||
#include "piconditionvar.h"
|
#include "piconditionvar.h"
|
||||||
#include "pithreadpoolexecutor.h"
|
#include "pithreadpoolexecutor.h"
|
||||||
#include "pithreadpoolloop.h"
|
#include "pithreadpoolloop.h"
|
||||||
|
#include "pithreadnotifier.h"
|
||||||
|
|
||||||
#endif // PITHREADMODULE_H
|
#endif // PITHREADMODULE_H
|
||||||
|
|||||||
39
libs/main/thread/pithreadnotifier.cpp
Normal file
39
libs/main/thread/pithreadnotifier.cpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
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 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pithreadnotifier.h"
|
||||||
|
|
||||||
|
|
||||||
|
PIThreadNotifier::PIThreadNotifier() : cnt(0) {}
|
||||||
|
|
||||||
|
|
||||||
|
void PIThreadNotifier::wait() {
|
||||||
|
m.lock();
|
||||||
|
while (cnt == 0) v.wait(m);
|
||||||
|
cnt--;
|
||||||
|
m.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIThreadNotifier::notifyOnce() {
|
||||||
|
m.lock();
|
||||||
|
cnt++;
|
||||||
|
v.notifyAll();
|
||||||
|
m.unlock();
|
||||||
|
}
|
||||||
52
libs/main/thread/pithreadnotifier.h
Normal file
52
libs/main/thread/pithreadnotifier.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*! @file pithreadnotifier.h
|
||||||
|
* @brief Class for simply notify and wait in different threads
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
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 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 PITHREADNOTIFIER_H
|
||||||
|
#define PITHREADNOTIFIER_H
|
||||||
|
|
||||||
|
#include "piconditionvar.h"
|
||||||
|
|
||||||
|
|
||||||
|
class PIP_EXPORT PIThreadNotifier {
|
||||||
|
public:
|
||||||
|
PIThreadNotifier();
|
||||||
|
|
||||||
|
//! Start waiting, return if other thread call \a notifyOnce().
|
||||||
|
//! If \a notifyOnce() has been called before, then returns immediately.
|
||||||
|
//! If notifyOnce() has been called "n" times, then returns immediately "n" times,
|
||||||
|
//! but only if wait in one thread.
|
||||||
|
//! If many threads waiting, then If notifyOnce() has been called "n" times,
|
||||||
|
//! All threads total returns "n" times in random sequence.
|
||||||
|
void wait();
|
||||||
|
|
||||||
|
//! Notify one waiting thread, wich waiting on \a wait() function.
|
||||||
|
//! If many threads waiting, then notify randomly one.
|
||||||
|
//! If call this "n" times, then notify any waiting threads totally "n" times.
|
||||||
|
void notifyOnce();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ullong cnt;
|
||||||
|
PIMutex m;
|
||||||
|
PIConditionVariable v;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PITHREADNOTIFIER_H
|
||||||
@@ -648,11 +648,11 @@ bool PITimer::stop(bool wait) {
|
|||||||
bool PITimer::waitForFinish(int timeout_msecs) {
|
bool PITimer::waitForFinish(int timeout_msecs) {
|
||||||
if (timeout_msecs < 0) {
|
if (timeout_msecs < 0) {
|
||||||
while (isRunning())
|
while (isRunning())
|
||||||
msleep(PIP_MIN_MSLEEP);
|
piMinSleep();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
PITimeMeasurer tm;
|
PITimeMeasurer tm;
|
||||||
while (isRunning() && tm.elapsed_m() < timeout_msecs)
|
while (isRunning() && tm.elapsed_m() < timeout_msecs)
|
||||||
msleep(PIP_MIN_MSLEEP);
|
piMinSleep();
|
||||||
return tm.elapsed_m() < timeout_msecs;
|
return tm.elapsed_m() < timeout_msecs;
|
||||||
}
|
}
|
||||||
|
|||||||
139
main.cpp
139
main.cpp
@@ -2,122 +2,27 @@
|
|||||||
|
|
||||||
|
|
||||||
int main(int argc, char * argv[]) {
|
int main(int argc, char * argv[]) {
|
||||||
|
PIThreadNotifier n;
|
||||||
PIVector<int> data(10, [](int i)->int{return i;});
|
int cnt1 = 0;
|
||||||
|
int cnt2 = 0;
|
||||||
piCout << data;
|
int cnt3 = 0;
|
||||||
|
PIThread t1([&n, &cnt1](){n.wait(); cnt1++; piMSleep(1);}, true);
|
||||||
PIThreadPoolLoop pool;
|
PIThread t2([&n, &cnt2](){n.wait(); cnt2++; piMSleep(2);}, true);
|
||||||
pool.setFunction([&](int i){
|
piCout << "created";
|
||||||
data[i] = data[i] + 10;
|
piMSleep(10);
|
||||||
});
|
piCout << "unlock" << cnt1 << cnt2 << cnt3;
|
||||||
pool.exec(0, data.size());
|
n.notifyOnce(); cnt3++;
|
||||||
|
piMSleep(10);
|
||||||
piCout << data;
|
piCout << "unlock" << cnt1 << cnt2 << cnt3;
|
||||||
|
n.notifyOnce(); cnt3++;
|
||||||
return 0;
|
piMSleep(10);
|
||||||
|
piCout << "run" << cnt1 << cnt2 << cnt3;
|
||||||
PIVector<int> x(20, [](int i) {return i;});
|
PIThread t3([&n, &cnt3](){n.notifyOnce(); cnt3++; piMSleep(1);}, true);
|
||||||
piCout << x;
|
piMSleep(20);
|
||||||
piCout << x.any([](int v) {return v == 10;});
|
t3.stop();
|
||||||
piCout << x.every([](int v) {return v > 0;});
|
piMSleep(100);
|
||||||
piCout << x.etries([](int v) {return v % 5 == 0;});
|
piCout << "exit" << cnt1 << cnt2 << cnt3;
|
||||||
piCout << x.indexWhere([](int v) {return v % 8 == 0;});
|
// m.unlock();
|
||||||
piCout << x.indexOf(4, -1);
|
// piMSleep(10);
|
||||||
piCout << x.lastIndexOf(1, 0);
|
|
||||||
piCout << x.lastIndexWhere([](int v) {return v % 8 == 0;});
|
|
||||||
PIVector<double> x2 = x.map<double>([](int v) {return v / 10.0;});
|
|
||||||
piCout << x2;
|
|
||||||
piCout << x.reduce<PIString>([](int v, PIString s){return s + PIString::fromNumber(v);});
|
|
||||||
piCout << x.removeWhere([](int v){return v % 2 == 0;});
|
|
||||||
piCout << x.getRange(8, 1);
|
|
||||||
piCout << x.getRange(8, 100);
|
|
||||||
|
|
||||||
piCout << "=====================";
|
|
||||||
|
|
||||||
PIDeque<int> y(20, [](int i) {return i;});
|
|
||||||
piCout << y;
|
|
||||||
piCout << y.any([](int v) {return v == 10;});
|
|
||||||
piCout << y.every([](int v) {return v > 0;});
|
|
||||||
piCout << y.etries([](int v) {return v % 5 == 0;});
|
|
||||||
piCout << y.indexWhere([](int v) {return v % 8 == 0;});
|
|
||||||
piCout << y.indexOf(4, -1);
|
|
||||||
piCout << y.lastIndexOf(1, 0);
|
|
||||||
piCout << y.lastIndexWhere([](int v) {return v % 8 == 0;});
|
|
||||||
PIDeque<double> y2 = y.map<double>([](int v) {return v / 10.0;});
|
|
||||||
piCout << y2;
|
|
||||||
piCout << y.reduce<PIString>([](int v, PIString s){return s + PIString::fromNumber(v);});
|
|
||||||
piCout << y.removeWhere([](int v){return v % 2 == 0;});
|
|
||||||
piCout << y.getRange(8, 1);
|
|
||||||
piCout << y.getRange(8, 100);
|
|
||||||
return 0; // TODO:
|
|
||||||
|
|
||||||
PIByteArray rnd;
|
|
||||||
rnd.resize(1024*1024, 'x');
|
|
||||||
PICLI cli(argc, argv);
|
|
||||||
PITimer tm;
|
|
||||||
cli.addArgument("connect", true);
|
|
||||||
cli.addArgument("name", true);
|
|
||||||
PICloudClient c("127.0.0.1:10101");
|
|
||||||
// c.setReopenEnabled(true);
|
|
||||||
PICloudServer s("127.0.0.1:10101");
|
|
||||||
PIVector<PICloudServer::Client *> clients;
|
|
||||||
CONNECTL(&tm, tickEvent, ([&](void *, int){
|
|
||||||
if (c.isConnected()) {
|
|
||||||
PIString str = "ping";
|
|
||||||
piCout << "[Client] send:" << str;
|
|
||||||
c.write(str.toByteArray());
|
|
||||||
}
|
|
||||||
if (s.isRunning()) {
|
|
||||||
for (auto cl : clients) {
|
|
||||||
if (cl->isOpened()) {
|
|
||||||
PIString str = "ping_S";
|
|
||||||
piCout << "[Server] send to" << cl << ":" << str;
|
|
||||||
cl->write(str.toByteArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
CONNECTL(&c, threadedReadEvent, ([&](uchar * readed, int size){
|
|
||||||
PIByteArray ba(readed, size);
|
|
||||||
if (size < 1024) {
|
|
||||||
PIString str = PIString(ba);
|
|
||||||
piCout << "[Client] data:" << str;
|
|
||||||
if (str == "ping_S") c.write(PIString("pong_S").toByteArray());
|
|
||||||
} else piCout << "[Client] blob:" << size;
|
|
||||||
}));
|
|
||||||
CONNECTL(&c, connected, ([](){piCout << "connected";}));
|
|
||||||
CONNECTL(&c, disconnected, ([](){piCout << "disconnected";}));
|
|
||||||
CONNECTL(&s, newConnection, ([&](PICloudServer::Client * cl){
|
|
||||||
piCout << "[Server] new client:" << cl;
|
|
||||||
clients << cl;
|
|
||||||
CONNECTL(cl, threadedReadEvent, ([&c, &s, cl, &rnd](uchar * readed, int size){
|
|
||||||
PIByteArray ba(readed, size);
|
|
||||||
PIString str = PIString(ba);
|
|
||||||
piCout << "[Server] data from" << cl << ":" << str;
|
|
||||||
if (str == "ping") {
|
|
||||||
cl->write(PIString("pong").toByteArray());
|
|
||||||
cl->write(rnd);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
CONNECTL(cl, closed, ([&clients, cl](){
|
|
||||||
cl->stop();
|
|
||||||
clients.removeAll(cl);
|
|
||||||
cl->deleteLater();
|
|
||||||
}));
|
|
||||||
cl->startThreadedRead();
|
|
||||||
}));
|
|
||||||
if (cli.hasArgument("name")) s.setServerName(cli.argumentValue("name"));
|
|
||||||
if (cli.hasArgument("connect")) {
|
|
||||||
c.setServerName(cli.argumentValue("connect"));
|
|
||||||
c.startThreadedRead();
|
|
||||||
} else {
|
|
||||||
s.startThreadedRead();
|
|
||||||
}
|
|
||||||
tm.start(1000);
|
|
||||||
PIKbdListener ls;
|
|
||||||
ls.enableExitCapture(PIKbdListener::F10);
|
|
||||||
ls.start();
|
|
||||||
WAIT_FOR_EXIT
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
73
main_picloud_test.cpp
Normal file
73
main_picloud_test.cpp
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#include "pip.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char * argv[]) {
|
||||||
|
PIByteArray rnd;
|
||||||
|
rnd.resize(1024*1024, 'x');
|
||||||
|
PICLI cli(argc, argv);
|
||||||
|
PITimer tm;
|
||||||
|
cli.addArgument("connect", true);
|
||||||
|
cli.addArgument("name", true);
|
||||||
|
PICloudClient c("127.0.0.1:10101");
|
||||||
|
// c.setReopenEnabled(true);
|
||||||
|
PICloudServer s("127.0.0.1:10101");
|
||||||
|
PIVector<PICloudServer::Client *> clients;
|
||||||
|
CONNECTL(&tm, tickEvent, ([&](void *, int){
|
||||||
|
if (c.isConnected()) {
|
||||||
|
PIString str = "ping";
|
||||||
|
piCout << "[Client] send:" << str;
|
||||||
|
c.write(str.toByteArray());
|
||||||
|
}
|
||||||
|
if (s.isRunning()) {
|
||||||
|
for (auto cl : clients) {
|
||||||
|
if (cl->isOpened()) {
|
||||||
|
PIString str = "ping_S";
|
||||||
|
piCout << "[Server] send to" << cl << ":" << str;
|
||||||
|
cl->write(str.toByteArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
CONNECTL(&c, threadedReadEvent, ([&](uchar * readed, int size){
|
||||||
|
PIByteArray ba(readed, size);
|
||||||
|
if (size < 1024) {
|
||||||
|
PIString str = PIString(ba);
|
||||||
|
piCout << "[Client] data:" << str;
|
||||||
|
if (str == "ping_S") c.write(PIString("pong_S").toByteArray());
|
||||||
|
} else piCout << "[Client] blob:" << size;
|
||||||
|
}));
|
||||||
|
CONNECTL(&c, connected, ([](){piCout << "connected";}));
|
||||||
|
CONNECTL(&c, disconnected, ([](){piCout << "disconnected";}));
|
||||||
|
CONNECTL(&s, newConnection, ([&](PICloudServer::Client * cl){
|
||||||
|
piCout << "[Server] new client:" << cl;
|
||||||
|
clients << cl;
|
||||||
|
CONNECTL(cl, threadedReadEvent, ([&c, &s, cl, &rnd](uchar * readed, int size){
|
||||||
|
PIByteArray ba(readed, size);
|
||||||
|
PIString str = PIString(ba);
|
||||||
|
piCout << "[Server] data from" << cl << ":" << str;
|
||||||
|
if (str == "ping") {
|
||||||
|
cl->write(PIString("pong").toByteArray());
|
||||||
|
cl->write(rnd);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
CONNECTL(cl, closed, ([&clients, cl](){
|
||||||
|
cl->stop();
|
||||||
|
clients.removeAll(cl);
|
||||||
|
cl->deleteLater();
|
||||||
|
}));
|
||||||
|
cl->startThreadedRead();
|
||||||
|
}));
|
||||||
|
if (cli.hasArgument("name")) s.setServerName(cli.argumentValue("name"));
|
||||||
|
if (cli.hasArgument("connect")) {
|
||||||
|
c.setServerName(cli.argumentValue("connect"));
|
||||||
|
c.startThreadedRead();
|
||||||
|
} else {
|
||||||
|
s.startThreadedRead();
|
||||||
|
}
|
||||||
|
tm.start(1000);
|
||||||
|
PIKbdListener ls;
|
||||||
|
ls.enableExitCapture(PIKbdListener::F10);
|
||||||
|
ls.start();
|
||||||
|
WAIT_FOR_EXIT
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -88,7 +88,7 @@ TEST_F(ConditionVariable, wait_is_protected_unblock_when_notifyOne) {
|
|||||||
// Missing unlock
|
// Missing unlock
|
||||||
});
|
});
|
||||||
variable->notifyOne();
|
variable->notifyOne();
|
||||||
msleep(WAIT_THREAD_TIME_MS);
|
piMSleep(WAIT_THREAD_TIME_MS);
|
||||||
ASSERT_FALSE(m.tryLock());
|
ASSERT_FALSE(m.tryLock());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ TEST_F(ConditionVariable, wait_condition_is_check_condition_when_notifyOne) {
|
|||||||
isConditionChecked = false;
|
isConditionChecked = false;
|
||||||
m.unlock();
|
m.unlock();
|
||||||
variable->notifyOne();
|
variable->notifyOne();
|
||||||
msleep(threadStartTime + 1);
|
piMSleep(threadStartTime + 1);
|
||||||
m.lock();
|
m.lock();
|
||||||
ASSERT_TRUE(isConditionChecked);
|
ASSERT_TRUE(isConditionChecked);
|
||||||
m.unlock();
|
m.unlock();
|
||||||
@@ -198,6 +198,6 @@ TEST_F(ConditionVariable, waitFor_is_unblock_when_condition_and_notifyOne) {
|
|||||||
condition = true;
|
condition = true;
|
||||||
m.unlock();
|
m.unlock();
|
||||||
variable->notifyOne();
|
variable->notifyOne();
|
||||||
msleep(WAIT_THREAD_TIME_MS);
|
piMSleep(WAIT_THREAD_TIME_MS);
|
||||||
ASSERT_FALSE(thread->isRunning());
|
ASSERT_FALSE(thread->isRunning());
|
||||||
}
|
}
|
||||||
|
|||||||
34
tests/concurrent/pithreadnotifier_test.cpp
Normal file
34
tests/concurrent/pithreadnotifier_test.cpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "pithreadnotifier.h"
|
||||||
|
|
||||||
|
|
||||||
|
TEST(PIThreadNotifierTest, One) {
|
||||||
|
PIThreadNotifier n;
|
||||||
|
int cnt = 0;
|
||||||
|
PIThread t1([&n, &cnt](){n.wait(); cnt++;}, true);
|
||||||
|
piMSleep(10);
|
||||||
|
n.notifyOnce();
|
||||||
|
piMSleep(10);
|
||||||
|
ASSERT_EQ(cnt, 1);
|
||||||
|
n.notifyOnce();
|
||||||
|
piMSleep(10);
|
||||||
|
ASSERT_EQ(cnt, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(PIThreadNotifierTest, Two) {
|
||||||
|
PIThreadNotifier n;
|
||||||
|
int cnt1 = 0;
|
||||||
|
int cnt2 = 0;
|
||||||
|
int cnt3 = 0;
|
||||||
|
PIThread t1([&n, &cnt1](){n.wait(); cnt1++; piMSleep(2);}, true);
|
||||||
|
PIThread t2([&n, &cnt2](){n.wait(); cnt2++; piMSleep(2);}, true);
|
||||||
|
PIThread t3([&n, &cnt3](){n.notifyOnce(); cnt3++; piMSleep(1);}, true);
|
||||||
|
piMSleep(20);
|
||||||
|
t3.stop(true);
|
||||||
|
piMSleep(100);
|
||||||
|
t1.stop();
|
||||||
|
t2.stop();
|
||||||
|
ASSERT_EQ(cnt1+cnt2, cnt3);
|
||||||
|
}
|
||||||
|
|
||||||
51
tests/piobject/delete_later.cpp
Normal file
51
tests/piobject/delete_later.cpp
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "piobject.h"
|
||||||
|
|
||||||
|
std::atomic<int> obj_cnt;
|
||||||
|
|
||||||
|
class Send: public PIObject {
|
||||||
|
PIOBJECT(Send)
|
||||||
|
public:
|
||||||
|
Send() {obj_cnt++;}
|
||||||
|
~Send() {obj_cnt--;}
|
||||||
|
EVENT1(ev, PIObject * , o)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Recv: public PIObject {
|
||||||
|
PIOBJECT(Recv)
|
||||||
|
public:
|
||||||
|
Recv() {obj_cnt++;}
|
||||||
|
~Recv() {obj_cnt--;}
|
||||||
|
EVENT_HANDLER1(void, eh, PIObject * , o) {
|
||||||
|
o->deleteLater();
|
||||||
|
piMSleep(10);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TEST(Piobject, deleteLater) {
|
||||||
|
obj_cnt = 0;
|
||||||
|
Send * s = new Send();
|
||||||
|
Recv * r = new Recv();
|
||||||
|
CONNECTU(s, ev, r, eh);
|
||||||
|
s->ev(r);
|
||||||
|
r->deleteLater();
|
||||||
|
s->deleteLater();
|
||||||
|
piMSleep(100);
|
||||||
|
ASSERT_EQ(obj_cnt, 0);
|
||||||
|
|
||||||
|
PIVector<Send *> s2;
|
||||||
|
s2.resize(100, new Send());
|
||||||
|
for (auto o : s2) o->deleteLater();
|
||||||
|
piMSleep(10);
|
||||||
|
ASSERT_EQ(obj_cnt, 0);
|
||||||
|
s2.clear();
|
||||||
|
|
||||||
|
PIVector<Recv *> r2;
|
||||||
|
r2.resize(100, [](size_t i){return new Recv();});
|
||||||
|
for (auto o : r2) o->deleteLater();
|
||||||
|
piMSleep(10);
|
||||||
|
ASSERT_EQ(obj_cnt, 0);
|
||||||
|
r2.clear();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user