merged concurrent to main library

removed PIConditionLock, use PIMutex instead
This commit is contained in:
2020-07-30 18:50:42 +03:00
parent 4dd59132d5
commit 2ffc457566
31 changed files with 558 additions and 2176 deletions

View File

@@ -1,51 +0,0 @@
/*
PIP - Platform Independent Primitives
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 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 PICONDITIONLOCK_H
#define PICONDITIONLOCK_H
#include "pibase.h"
/**
* @brief Continued
*/
class PIP_EXPORT PIConditionLock {
public:
NO_COPY_CLASS(PIConditionLock)
explicit PIConditionLock();
~PIConditionLock();
//! \brief lock
void lock();
//! \brief unlock
void unlock();
//! \brief tryLock
bool tryLock();
void * handle();
private:
PRIVATE_DECLARATION
};
#endif // PICONDITIONLOCK_H

View File

@@ -1,461 +0,0 @@
/*! \file piconsole.h
* \brief Console output class
*/
/*
PIP - Platform Independent Primitives
Console output/input
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICONSOLE_H
#define PICONSOLE_H
#include "pikbdlistener.h"
class PIProtocol;
class PIDiagnostics;
class PISystemMonitor;
class PIPeer;
class PITimer;
class PIP_EXPORT PIConsole: public PIThread
{
PIOBJECT_SUBCLASS(PIConsole, PIThread)
public:
//! Constructs %PIConsole with key handler "slot" and if "startNow" start it
explicit PIConsole(bool startNow = true, PIKbdListener::KBFunc slot = 0);
~PIConsole();
//! Variables output format
enum Format {
Normal /** Default console format */ = 0x01,
Bold /** Bold text */ = 0x02,
Faint = 0x04,
Italic = 0x08,
Underline /** Underlined text */ = 0x10,
Blink /** Blinked text */ = 0x20,
Inverse /** Swap text and background colors */ = 0x40,
Black /** Black text */ = 0x100,
Red /** Red text */ = 0x200,
Green /** Green text */ = 0x400,
Yellow /** Yellow text */ = 0x800,
Blue /** Blue text */ = 0x1000,
Magenta /** Magenta text */ = 0x2000,
Cyan /** Cyan text */ = 0x4000,
White /** White text */ = 0x8000,
BackBlack /** Black background */ = 0x10000,
BackRed /** Red background */ = 0x20000,
BackGreen /** Green background */ = 0x40000,
BackYellow /** Yellow background */ = 0x80000,
BackBlue /** Blue background */ = 0x100000,
BackMagenta /** Magenta background */ = 0x200000,
BackCyan /** Cyan background */ = 0x400000,
BackWhite /** White background */ = 0x800000,
Dec /** Decimal base for integers */ = 0x1000000,
Hex /** Hexadecimal base for integers */ = 0x2000000,
Oct /** Octal base for integers */ = 0x4000000,
Bin /** Binary base for integers */ = 0x8000000,
Scientific /** Scientific representation of floats */ = 0x10000000,
SystemTimeSplit /** PISystemTime split representation (* s, * ns) */ = 0x20000000,
SystemTimeSeconds /** PISystemTime seconds representation (*.* s) */ = 0x40000000
};
//! Column labels alignment
enum Alignment {
Nothing /** No alignment */ ,
Left /** Labels align left and variables align left */ ,
Right /** Labels align right and variables align left */
};
typedef PIFlags<PIConsole::Format> FormatFlags;
//! Add to current tab to column "column" string "name" with format "format"
void addString(const PIString & name, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const PIString * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const char * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const bool * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const short * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const int * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const long * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const llong * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const uchar * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const ushort * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const uint * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const ulong * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const ullong * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const float * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const double * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const PISystemTime * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
void addVariable(const PIString & name, const PIDiagnostics * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
void addVariable(const PIString & name, const PISystemMonitor * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" bits field with label "name", pointer "ptr" and format "format"
void addBitVariable(const PIString & name, const void * ptr, int fromBit, int bitsCount, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" "count" empty lines
void addEmptyLine(int column = 1, uint count = 1);
PIString getString(int x, int y);
short getShort(int x, int y) {return getString(x, y).toShort();}
int getInt(int x, int y) {return getString(x, y).toInt();}
float getFloat(int x, int y) {return getString(x, y).toFloat();}
double getDouble(int x, int y) {return getString(x, y).toDouble();}
PIString getString(const PIString & name);
short getShort(const PIString & name) {return getString(name).toShort();}
int getInt(const PIString & name) {return getString(name).toInt();}
float getFloat(const PIString & name) {return getString(name).toFloat();}
double getDouble(const PIString & name) {return getString(name).toDouble();}
//! Returns tabs count
uint tabsCount() const {return tabs.size();}
//! Returns current tab name
PIString currentTab() const {return tabs[cur_tab].name;}
//! Returns current tab index
int currentTabIndex() const {return cur_tab;}
//! Add new tab with name "name", bind key "bind_key" and returns this tab index
int addTab(const PIString & name, char bind_key = 0);
//! Remove tab with index "index"
void removeTab(uint index);
//! Remove tab with name "name"
void removeTab(const PIString & name);
//! Clear content of tab with index "index"
void clearTab(uint index);
//! Clear content of tab with name "name"
void clearTab(const PIString & name);
//! Set current tab to tab with index "index", returns if tab exists
bool setTab(uint index);
//! Set current tab to tab with name "name", returns if tab exists
bool setTab(const PIString & name);
//! Set tab with index "index" bind key to "bind_key", returns if tab exists
bool setTabBindKey(uint index, char bind_key);
//! Set tab with name "name" bind key to "bind_key", returns if tab exists
bool setTabBindKey(const PIString & name, char bind_key);
//! Remove all tabs and if "clearScreen" clear the screen
void clearTabs(bool clearScreen = true) {if (clearScreen && isRunning()) {toUpperLeft(); clearScreenLower();} tabs.clear();}
//! Set custom status text of current tab to "str"
void addCustomStatus(const PIString & str) {tabs[cur_tab].status = str;}
//! Clear custom status text of current tab
void clearCustomStatus() {tabs[cur_tab].status.clear();}
//! Returns default alignment
Alignment defaultAlignment() const {return def_align;}
//! Set default alignment to "align"
void setDefaultAlignment(Alignment align) {def_align = align;}
//! Set column "col" alignment to "align"
void setColumnAlignment(int col, Alignment align) {if (col < 0 || col >= columns().size_s()) return; column(col).alignment = align;}
//! Set all columns of all tabs alignment to "align"
void setColumnAlignmentToAll(Alignment align) {piForeach (Tab & i, tabs) piForeach (Column & j, i.columns) j.alignment = align; fillLabels();}
//! Directly call function from \a PIKbdListener
void enableExitCapture(char key = 'Q') {listener->enableExitCapture(key);}
//! Directly call function from \a PIKbdListener
void disableExitCapture() {listener->disableExitCapture();}
//! Directly call function from \a PIKbdListener
bool exitCaptured() const {return listener->exitCaptured();}
//! Directly call function from \a PIKbdListener
char exitKey() const {return listener->exitKey();}
int windowWidth() const {return width;}
int windowHeight() const {return height;}
PIString fstr(FormatFlags f);
void update();
void pause(bool yes) {pause_ = yes;}
// Server functions
void startServer(const PIString & name);
void stopPeer();
bool isServerStarted() const {return peer != 0;}
PIStringList clients() const;
// Client functions
void listenServers();
PIStringList availableServers() const;
PIString selectedServer() const {return server_name;}
void connectToServer(const PIString & name);
void disconnect();
bool isConnected() const {return state == Connected;}
void toUpperLeft();
void moveRight(int n = 1);
void moveLeft(int n = 1);
void moveTo(int x = 0, int y = 0);
void clearScreen();
void clearScreenLower();
void clearLine();
void newLine();
void hideCursor();
void showCursor();
EVENT_HANDLER0(void, clearVariables) {clearVariables(true);}
EVENT_HANDLER1(void, clearVariables, bool, clearScreen);
EVENT_HANDLER0(void, waitForFinish) {WAIT_FOR_EXIT}
EVENT_HANDLER0(void, start) {start(false);}
EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();}
EVENT_HANDLER0(void, stop) {stop(false);}
EVENT_HANDLER1(void, stop, bool, clear);
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
//! \handlers
//! \{
//! \fn void waitForFinish()
//! \brief block until finished (exit key will be pressed)
//! \fn void clearVariables(bool clearScreen = true)
//! \brief Remove all columns at current tab and if "clearScreen" clear the screen
//! \fn void start(bool wait = false)
//! \brief Start console output and if "wait" block until finished (exit key will be pressed)
//! \fn void stop(bool clear = false)
//! \brief Stop console output and if "clear" clear the screen
//! \}
//! \events
//! \{
//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data)
//! \brief Raise on key "key" pressed, "data" is pointer to %PIConsole object
//! \}
private:
void begin();
void run();
void fillLabels();
void status();
void checkColumn(uint col) {while (columns().size() < col) columns().push_back(Column(def_align));}
int bitsValue(const void * src, int offset, int count) const;
const char * toBin(const void * d, int s);
inline void printLine(const PIString & str, int dx = 0, FormatFlags format = PIConsole::Normal);
inline int printValue(const PIString & str, FormatFlags format = PIConsole::Normal);
inline int printValue(const char * str, FormatFlags format = PIConsole::Normal);
inline int printValue(const bool value, FormatFlags format = PIConsole::Normal);
inline int printValue(const int value, FormatFlags format = PIConsole::Normal);
inline int printValue(const long value, FormatFlags format = PIConsole::Normal);
inline int printValue(const llong value, FormatFlags format = PIConsole::Normal);
inline int printValue(const float value, FormatFlags format = PIConsole::Normal);
inline int printValue(const double value, FormatFlags format = PIConsole::Normal);
inline int printValue(const char value, FormatFlags format = PIConsole::Normal);
inline int printValue(const short value, FormatFlags format = PIConsole::Normal);
inline int printValue(const uchar value, FormatFlags format = PIConsole::Normal);
inline int printValue(const ushort value, FormatFlags format = PIConsole::Normal);
inline int printValue(const uint value, FormatFlags format = PIConsole::Normal);
inline int printValue(const ulong value, FormatFlags format = PIConsole::Normal);
inline int printValue(const ullong value, FormatFlags format = PIConsole::Normal);
inline int printValue(const PISystemTime & value, FormatFlags format = PIConsole::Normal);
static void key_event(PIKbdListener::KeyEvent key, void * t);
struct Variable {
Variable() {nx = ny = type = offset = bitFrom = bitCount = size = 0; format = Normal; remote = false; ptr = 0; id = 1;}
Variable(const Variable & src) {remote = src.remote; name = src.name; format = src.format; type = src.type; offset = src.offset; size = src.size;
bitFrom = src.bitFrom; bitCount = src.bitCount; ptr = src.ptr; nx = src.nx; ny = src.ny; rdata = src.rdata; id = src.id;}
bool isEmpty() const {return (remote ? false : ptr == 0);}
const void * data() {return (remote ? rdata.data() : ptr);}
void writeData(PIByteArray & ba) {
if (remote) ba << rdata;
else {
if (type == 0) ba << (*(PIString * )ptr);
else ba << PIByteArray::RawData(ptr, size);
}
}
PIString name;
FormatFlags format;
int nx;
int ny;
int type;
int offset;
int bitFrom;
int bitCount;
int size;
int id;
bool remote;
const void * ptr;
PIByteArray rdata;
void operator =(const Variable & src) {remote = src.remote; name = src.name; format = src.format; type = src.type; offset = src.offset; size = src.size;
bitFrom = src.bitFrom; bitCount = src.bitCount; ptr = src.ptr; nx = src.nx; ny = src.ny; rdata = src.rdata; id = src.id;}
};
struct VariableContent {
int id;
PIByteArray rdata;
};
struct Column {
Column(Alignment align = PIConsole::Right) {variables.reserve(32); alignment = align;}
PIVector<Variable> variables;
Alignment alignment;
uint size() const {return variables.size();}
Variable & operator [](int index) {return variables[index];}
const Variable & operator [](int index) const {return variables[index];}
void push_back(const Variable & v) {variables.push_back(v);}
void operator =(const Column & src) {variables = src.variables; alignment = src.alignment;}
};
struct Tab {
Tab(PIString n = "", char k = 0) {columns.reserve(8); name = n; key = k;}
PIVector<Column> columns;
PIString name;
PIString status;
char key;
};
enum ConnectedState {Disconnected, FetchingData, Committing, Connected};
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::VariableContent & v);
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::VariableContent & v);
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Variable & v);
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Variable & v);
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Column & v);
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Column & v);
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Tab & v);
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Tab & v);
PIVector<Column> & columns() {return tabs[cur_tab].columns;}
Column & column(int index) {return tabs[cur_tab].columns[index - 1];}
int couts(const PIString & v);
int couts(const char * v);
int couts(const bool v);
int couts(const char v);
int couts(const short v);
int couts(const int v);
int couts(const long v);
int couts(const llong v);
int couts(const uchar v);
int couts(const ushort v);
int couts(const uint v);
int couts(const ulong v);
int couts(const ullong v);
int couts(const float v);
int couts(const double v);
int couts(const PISystemTime & v);
struct RemoteClient;
void serverSendInfo();
void serverSendData();
RemoteClient & remoteClient(const PIString & fname);
EVENT_HANDLER2(void, peerReceived, const PIString &, from, const PIByteArray &, data);
EVENT_HANDLER2(void, peerTimer, void * , data, int, delim);
EVENT_HANDLER1(void, peerDisconnectedEvent, const PIString &, name);
PRIVATE_DECLARATION
PIVector<Tab> tabs;
PIString binstr, rstr;
PIByteArray rba;
Variable tv;
PIKbdListener * listener;
Alignment def_align;
PIKbdListener::KBFunc ret_func;
int width, height, pwidth, pheight, col_wid, num_format, systime_format;
uint max_y;
int vid;
uint cur_tab, col_cnt;
PIPeer * peer;
PITimer * peer_timer;
PITimeMeasurer peer_tm;
PIString server_name;
bool server_mode, pause_;
ConnectedState state;
struct RemoteClient {
RemoteClient(const PIString & n = "") {name = n; state = Disconnected;}
PIString name;
ConnectedState state;
};
PIVector<RemoteClient> remote_clients;
};
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::VariableContent & v) {ba << v.id << v.rdata; return ba;}
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::VariableContent & v) {ba >> v.id; ba >> v.rdata; return ba;}
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Variable & v) {ba << v.name << v.id << (int)v.format << v.type << v.size << v.bitFrom << v.bitCount; return ba;}
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Variable & v) {ba >> v.name >> v.id >> (int & )v.format >> v.type >> v.size >> v.bitFrom >> v.bitCount; return ba;}
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Column & v) {ba << (int)v.alignment << v.variables; return ba;}
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Column & v) {int a; ba >> a >> v.variables; v.alignment = (PIConsole::Alignment)a; return ba;}
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Tab & v) {ba << v.name << v.status << (uchar)v.key << v.columns; return ba;}
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Tab & v) {ba >> v.name >> v.status >> (uchar&)v.key >> v.columns; return ba;}
#endif // PICONSOLE_H

View File

@@ -21,7 +21,6 @@
#define PICONSOLEMODULE_H
#include "pikbdlistener.h"
#include "piconsole.h"
#include "piscreen.h"
#include "piscreentiles.h"

View File

@@ -49,6 +49,9 @@ public:
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(pid_size, f);
}
inline PIDeque(PIDeque<T> && other): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
swap(other);
}
inline virtual ~PIDeque() {
//piCout << "~PIDeque";
PIINTROSPECTION_CONTAINER_DELETE(T)
@@ -66,6 +69,12 @@ public:
return *this;
}
inline PIDeque<T> & operator =(PIDeque<T> && other) {
if (this == &other) return *this;
swap(other);
return *this;
}
typedef T value_type;
class iterator {
@@ -256,6 +265,23 @@ public:
elementNew(pid_data + pid_start + index, v);
return *this;
}
inline PIDeque<T> & insert(size_t index, T && v) {
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
alloc(pid_size + 1, true);
if (index < pid_size - 1) {
size_t os = pid_size - index - 1;
memmove((void*)(&(pid_data[index + pid_start + 1])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
}
} else {
alloc(pid_size + 1, false, -1);
if (index > 0)
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T));
}
PIINTROSPECTION_CONTAINER_USED(T, 1)
elementNew(pid_data + pid_start + index, v);
return *this;
}
inline PIDeque<T> & insert(size_t index, const PIDeque<T> & other) {
if (other.isEmpty()) return *this;
assert(&other != this);
@@ -336,7 +362,14 @@ public:
elementNew(pid_data + pid_start + pid_size - 1, v);
return *this;
}
inline PIDeque<T> & push_back(T && v) {
alloc(pid_size + 1, true);
PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(pid_data + pid_start + pid_size - 1, v);
return *this;
}
inline PIDeque<T> & append(const T & v) {return push_back(v);}
inline PIDeque<T> & append(T && v) {return push_back(v);}
inline PIDeque<T> & append(const PIDeque<T> & t) {
assert(&t != this);
size_t ps = pid_size;
@@ -345,6 +378,7 @@ public:
return *this;
}
inline PIDeque<T> & operator <<(const T & v) {return push_back(v);}
inline PIDeque<T> & operator <<(T && v) {return push_back(v);}
inline PIDeque<T> & operator <<(const PIDeque<T> & t) {return append(t);}
inline PIDeque<T> & push_front(const T & v) {insert(0, v); return *this;}
@@ -412,6 +446,7 @@ private:
}
}
inline void elementNew(T * to, const T & from) {new(to)T(from);}
inline void elementNew(T * to, T && from) {piSwap(*to, from);}
inline void elementDelete(T & from) {from.~T();}
inline void dealloc() {
if ((uchar*)pid_data != 0) free((uchar*)pid_data);
@@ -485,6 +520,7 @@ private:
template<> inline void PIDeque<T>::newT(T * dst, const T * src, size_t s) {PIINTROSPECTION_CONTAINER_USED(T, s); memcpy((void*)(dst), (const void*)(src), s * sizeof(T));} \
template<> inline void PIDeque<T>::deleteT(T *, size_t sz) {PIINTROSPECTION_CONTAINER_UNUSED(T, sz);} \
template<> inline void PIDeque<T>::elementNew(T * to, const T & from) {(*to) = from;} \
template<> inline void PIDeque<T>::elementNew(T * to, T && from) {(*to) = from;} \
template<> inline void PIDeque<T>::elementDelete(T &) {;} \
template<> inline PIDeque<T> & PIDeque<T>::_resizeRaw(size_t new_size) { \
if (new_size > pid_size) { \

View File

@@ -74,6 +74,7 @@ class PIMap {
public:
PIMap() {;}
PIMap(const PIMap<Key, T> & other) {*this = other;}
PIMap(PIMap<Key, T> && other) {swap(other);}
virtual ~PIMap() {;}
PIMap<Key, T> & operator =(const PIMap<Key, T> & other) {
@@ -84,6 +85,12 @@ public:
return *this;
}
PIMap<Key, T> & operator =(PIMap<Key, T> && other) {
if (this == &other) return *this;
swap(other);
return *this;
}
typedef T mapped_type;
typedef Key key_type;
typedef PIPair<Key, T> value_type;

View File

@@ -48,6 +48,9 @@ public:
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(piv_size, f);
}
inline PIVector(PIVector<T> && other): piv_data(0), piv_size(0), piv_rsize(0) {
swap(other);
}
inline virtual ~PIVector() {
PIINTROSPECTION_CONTAINER_DELETE(T)
PIINTROSPECTION_CONTAINER_FREE(T, (piv_rsize))
@@ -65,6 +68,12 @@ public:
return *this;
}
inline PIVector<T> & operator =(PIVector<T> && other) {
if (this == &other) return *this;
swap(other);
return *this;
}
typedef T value_type;
class iterator {
@@ -253,6 +262,16 @@ public:
elementNew(piv_data + index, v);
return *this;
}
inline PIVector<T> & insert(size_t index, T && v) {
alloc(piv_size + 1);
if (index < piv_size - 1) {
size_t os = piv_size - index - 1;
memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T));
}
PIINTROSPECTION_CONTAINER_USED(T, 1)
elementNew(piv_data + index, v);
return *this;
}
inline PIVector<T> & insert(size_t index, const PIVector<T> & other) {
if (other.isEmpty()) return *this;
assert(&other != this);
@@ -320,7 +339,14 @@ public:
elementNew(piv_data + piv_size - 1, v);
return *this;
}
inline PIVector<T> & push_back(T && v) {
alloc(piv_size + 1);
PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(piv_data + piv_size - 1, v);
return *this;
}
inline PIVector<T> & append(const T & v) {return push_back(v);}
inline PIVector<T> & append(T && v) {return push_back(v);}
inline PIVector<T> & append(const PIVector<T> & other) {
assert(&other != this);
size_t ps = piv_size;
@@ -329,6 +355,7 @@ public:
return *this;
}
inline PIVector<T> & operator <<(const T & v) {return push_back(v);}
inline PIVector<T> & operator <<(T && v) {return push_back(v);}
inline PIVector<T> & operator <<(const PIVector<T> & other) {return append(other);}
inline PIVector<T> & push_front(const T & v) {insert(0, v); return *this;}
@@ -405,6 +432,7 @@ private:
}
}
inline void elementNew(T * to, const T & from) {new(to)T(from);}
inline void elementNew(T * to, T && from) {piSwap(*to, from);}
inline void elementDelete(T & from) {from.~T();}
inline void dealloc() {
if ((uchar*)piv_data != 0) free((uchar*)piv_data);
@@ -434,6 +462,7 @@ private:
template<> inline void PIVector<T>::newT(T * dst, const T * src, size_t s) {PIINTROSPECTION_CONTAINER_USED(T, s); memcpy((void*)(dst), (const void*)(src), s * sizeof(T));} \
template<> inline void PIVector<T>::deleteT(T *, size_t sz) {PIINTROSPECTION_CONTAINER_UNUSED(T, sz);} \
template<> inline void PIVector<T>::elementNew(T * to, const T & from) {(*to) = from;} \
template<> inline void PIVector<T>::elementNew(T * to, T && from) {(*to) = from;} \
template<> inline void PIVector<T>::elementDelete(T &) {;} \
template<> inline PIVector<T> & PIVector<T>::_resizeRaw(size_t new_size) { \
if (new_size > piv_size) { \

View File

@@ -18,9 +18,9 @@
*/
#include "piincludes_p.h"
#include "picout.h"
#include "piconsole.h"
#include "pibytearray.h"
#include "pistack.h"
#include "piobject.h"
#include "pistring_std.h"
#ifdef WINDOWS
# include <windows.h>

View File

@@ -19,7 +19,6 @@
#include "piincludes.h"
#include "piincludes_p.h"
#include "piconsole.h"
#include "pitime.h"
#ifndef QNX
# include <clocale>

View File

@@ -27,10 +27,9 @@
# include <iostream>
#endif
#include <atomic>
#include <mutex>
typedef std::mutex PIMutex;
//typedef std::lock_guard<std::mutex> PIMutexLocker;
class PIMutex;
class PIMutexLocker;
class PIObject;
class PIString;
class PIByteArray;

View File

@@ -51,6 +51,8 @@ public:
PIString(const PIString & o): PIDeque<PIChar>() {*this += o;}
PIString(PIString && o): PIDeque<PIChar>() {swap(o);}
//! Contructs string with single symbol "c"
PIString(const PIChar & c): PIDeque<PIChar>() {*this += c;}
@@ -89,6 +91,8 @@ public:
PIString & operator =(const PIString & o) {if (this == &o) return *this; clear(); *this += o; return *this;}
PIString & operator =(PIString && o) {if (this == &o) return *this; swap(o); return *this;}
/*! \brief Return c-string representation of string
* \details Converts content of string to c-string and return
* pointer to first char. This buffer is valid until new convertion

View File

@@ -83,6 +83,7 @@ public:
PIStringList & operator =(const PIStringList & o) {PIDeque<PIString>::operator=(o); return *this;}
PIStringList & operator <<(const PIString & str) {append(str); return *this;}
PIStringList & operator <<(PIString && str) {append(str); return *this;}
PIStringList & operator <<(const PIStringList & sl) {append(sl); return *this;}
};

View File

@@ -1,45 +0,0 @@
/*
PIP - Platform Independent Primitives
Text codings coder, based on "iconv"
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIP_FREERTOS
#include "picodec.h"
PIStringList PICodec::availableCodecs() {
exec("/usr/bin/iconv", "-l");
waitForFinish();
PIString str(readOutput());
str.cutLeft(str.find("\n "));
str.replaceAll("\n", "");
return str.split("//");
}
PIByteArray PICodec::exec_iconv(const PIString & from, const PIString & to, const PIByteArray & str) {
tf.openTemporary(PIIODevice::ReadWrite);
tf.clear();
tf << str;
tf.close();
exec("/usr/bin/iconv", PIStringList() << ("-f=" + from) << ("-t=" + to) << tf.path());
waitForFinish();
return readOutput();
}
#endif // PIP_FREERTOS

View File

@@ -1,54 +0,0 @@
/*
PIP - Platform Independent Primitives
Text codings coder, based on "iconv"
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICODEC_H
#define PICODEC_H
#ifndef PIP_FREERTOS
#include "piprocess.h"
class PIP_EXPORT PICodec: protected PIProcess
{
PIOBJECT(PICodec)
public:
PICodec(): PIProcess() {setGrabOutput(true);}
PICodec(const PIString & from, const PIString & to): PIProcess() {setCodings(from, to);}
~PICodec() {tf.remove();}
void setFromCoding(const PIString & from) {c_from = from;}
void setToCoding(const PIString & to) {c_to = to;}
void setCodings(const PIString & from, const PIString & to) {c_from = from; c_to = to;}
PIStringList availableCodecs();
PIString encode(PIString & str) {return PIString(exec_iconv(c_from, c_to, str.toByteArray()));}
PIString encode(const PIByteArray & str) {return PIString(exec_iconv(c_from, c_to, str));}
PIString decode(PIString & str) {return PIString(exec_iconv(c_to, c_from, str.toByteArray()));}
PIString decode(const PIByteArray & str) {return PIString(exec_iconv(c_to, c_from, str));}
private:
PIByteArray exec_iconv(const PIString & from, const PIString & to, const PIByteArray & str);
PIString c_from, c_to;
PIFile tf;
};
#endif // PIP_FREERTOS
#endif // PICODEC_H

View File

@@ -20,7 +20,6 @@
#ifndef PISYSTEMMODULE_H
#define PISYSTEMMODULE_H
#include "picodec.h"
#include "pisignals.h"
#include "pilibrary.h"
#include "pisysteminfo.h"

View File

@@ -17,8 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIP_TESTS_PIBLOCKINGDEQUEUE_H
#define PIP_TESTS_PIBLOCKINGDEQUEUE_H
#ifndef PIBLOCKINGDEQUEUE_H
#define PIBLOCKINGDEQUEUE_H
#include "pideque.h"
#include "piconditionvar.h"
@@ -140,14 +140,14 @@ public:
* return value is retrieved value
* @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available
*/
T poll(int timeoutMs, const T & defaultVal = T(), bool* isOk = nullptr) {
T poll(int timeoutMs, const T & defaultVal = T(), bool * isOk = nullptr) {
T t;
mutex.lock();
bool isNotEmpty = cond_var_add->waitFor(mutex, timeoutMs, [&]() { return !PIDeque<T>::isEmpty(); });
t = isNotEmpty ? T(PIDeque<T>::take_front()) : defaultVal;
mutex.unlock();
if (isNotEmpty) cond_var_rem->notifyOne();
if (isOk != nullptr) *isOk = isNotEmpty;
if (isOk) *isOk = isNotEmpty;
return t;
}
@@ -160,14 +160,14 @@ public:
* return value is retrieved value
* @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available
*/
T poll(const T & defaultVal = T(), bool* isOk = nullptr) {
T poll(const T & defaultVal = T(), bool * isOk = nullptr) {
T t;
mutex.lock();
bool isNotEmpty = !PIDeque<T>::isEmpty();
t = isNotEmpty ? T(PIDeque<T>::take_front()) : defaultVal;
mutex.unlock();
if (isNotEmpty) cond_var_rem->notifyOne();
if (isOk != nullptr) *isOk = isNotEmpty;
if (isOk) *isOk = isNotEmpty;
return t;
}
@@ -213,7 +213,7 @@ public:
*/
size_t drainTo(PIDeque<T>& other, size_t maxCount = SIZE_MAX) {
mutex.lock();
size_t count = maxCount > PIDeque<T>::size() ? PIDeque<T>::size() : maxCount;
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());
mutex.unlock();
return count;
@@ -235,11 +235,11 @@ public:
}
private:
PIConditionLock mutex;
PIConditionVariable* cond_var_add;
PIConditionVariable* cond_var_rem;
PIMutex mutex;
PIConditionVariable * cond_var_add, * cond_var_rem;
size_t max_size;
};
#endif //PIP_TESTS_PIBLOCKINGDEQUEUE_H
#endif // PIBLOCKINGDEQUEUE_H

View File

@@ -0,0 +1,141 @@
/*
PIP - Platform Independent Primitives
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 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 "piconditionvar.h"
#include "pithread.h"
#include "pitime.h"
#ifdef WINDOWS
# undef _WIN32_WINNT
# define _WIN32_WINNT 0x0600
# include <synchapi.h>
# include <windef.h>
# include <winbase.h>
#endif
PRIVATE_DEFINITION_START(PIConditionVariable)
#ifdef WINDOWS
CONDITION_VARIABLE nativeHandle;
#else
pthread_cond_t nativeHandle;
PIMutex * currentLock;
#endif
bool isDestroying;
PRIVATE_DEFINITION_END(PIConditionVariable)
PIConditionVariable::PIConditionVariable() {
#ifdef WINDOWS
InitializeConditionVariable(&PRIVATE->nativeHandle);
#else
PRIVATE->isDestroying = false;
PRIVATE->currentLock = nullptr;
memset(&(PRIVATE->nativeHandle), 0, sizeof(PRIVATE->nativeHandle));
pthread_cond_init(&PRIVATE->nativeHandle, NULL);
#endif
}
PIConditionVariable::~PIConditionVariable() {
#ifdef WINDOWS
#else
pthread_cond_destroy(&PRIVATE->nativeHandle);
#endif
}
void PIConditionVariable::wait(PIMutex& lk) {
#ifdef WINDOWS
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), INFINITE);
#else
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
#endif
}
void PIConditionVariable::wait(PIMutex& lk, const std::function<bool()>& condition) {
bool isCondition;
while (true) {
isCondition = condition();
if (isCondition) break;
#ifdef WINDOWS
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), INFINITE);
#else
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
#endif
if (PRIVATE->isDestroying) return;
}
}
bool PIConditionVariable::waitFor(PIMutex &lk, int timeoutMs) {
bool isNotTimeout;
#ifdef WINDOWS
isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs) != 0;
#else
timespec abstime = {.tv_sec = timeoutMs / 1000, .tv_nsec = timeoutMs * 1000 * 1000};
isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &abstime) == 0;
#endif
if (PRIVATE->isDestroying) return false;
return isNotTimeout;
}
bool PIConditionVariable::waitFor(PIMutex& lk, int timeoutMs, const std::function<bool()> &condition) {
bool isCondition;
PITimeMeasurer measurer;
while (true) {
isCondition = condition();
if (isCondition) break;
#ifdef WINDOWS
WINBOOL isTimeout = SleepConditionVariableCS(
&PRIVATE->nativeHandle,
(PCRITICAL_SECTION)lk.handle(),
timeoutMs - (int)measurer.elapsed_m());
if (isTimeout == 0) return false;
#else
int timeoutCurr = timeoutMs - (int)measurer.elapsed_m();
timespec abstime = {.tv_sec = timeoutCurr / 1000, .tv_nsec = timeoutCurr * 1000 * 1000};
bool isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &abstime) == 0;
if (isTimeout) return false;
#endif
if (PRIVATE->isDestroying) return false;
}
return true;
}
void PIConditionVariable::notifyOne() {
#ifdef WINDOWS
WakeConditionVariable(&PRIVATE->nativeHandle);
#else
pthread_cond_signal(&PRIVATE->nativeHandle);
#endif
}
void PIConditionVariable::notifyAll() {
#ifdef WINDOWS
WakeAllConditionVariable(&PRIVATE->nativeHandle);
#else
pthread_cond_broadcast(&PRIVATE->nativeHandle);
#endif
}

View File

@@ -20,14 +20,13 @@
#ifndef PICONDITIONVAR_H
#define PICONDITIONVAR_H
#include "piconditionlock.h"
#include "pithread.h"
/**
* @brief A condition variable is an object able to block the calling thread until notified to resume.
*
* It uses a PIConditionLock to lock the thread when one of its wait functions is called. The thread remains
* It uses a PIMutex to lock the thread when one of its wait functions is called. The thread remains
* blocked until woken up by another thread that calls a notification function on the same PIConditionVariable object.
*/
class PIP_EXPORT PIConditionVariable {
@@ -49,20 +48,20 @@ public:
void notifyAll();
/**
* @brief see wait(PIConditionLock&, const std::function<bool()>&)
* @brief see wait(PIMutex &, const std::function<bool()>&)
*/
virtual void wait(PIConditionLock& lk);
virtual void wait(PIMutex & lk);
/**
* @brief Wait until notified
*
* The execution of the current thread (which shall have locked with lk method PIConditionLock::lock()) is blocked
* The execution of the current thread (which shall have locked with lk method PIMutex::lock()) is blocked
* until notified.
*
* At the moment of blocking the thread, the function automatically calls lk.unlock() (PIConditionLock::unlock()),
* At the moment of blocking the thread, the function automatically calls lk.unlock() (PIMutex::unlock()),
* allowing other locked threads to continue.
*
* Once notified (explicitly, by some other thread), the function unblocks and calls lk.lock() (PIConditionLock::lock()),
* Once notified (explicitly, by some other thread), the function unblocks and calls lk.lock() (PIMutex::lock()),
* leaving lk in the same state as when the function was called. Then the function returns (notice that this last mutex
* locking may block again the thread before returning).
*
@@ -77,23 +76,23 @@ 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(PIConditionLock& lk, const std::function<bool()>& condition);
virtual void wait(PIMutex& lk, const std::function<bool()>& condition);
/**
* @brief see waitFor(PIConditionLock&, int, const std::function<bool()>&)
* @brief see waitFor(PIMutex &, int, const std::function<bool()>&)
*/
virtual bool waitFor(PIConditionLock& lk, int timeoutMs);
virtual bool waitFor(PIMutex & lk, int timeoutMs);
/**
* @brief Wait for timeout or until notified
*
* The execution of the current thread (which shall have locked with lk method PIConditionLock::lock()) is blocked
* The execution of the current thread (which shall have locked with lk method PIMutex::lock()) is blocked
* during timeoutMs, or until notified (if the latter happens first).
*
* At the moment of blocking the thread, the function automatically calls lk.lock() (PIConditionLock::lock()), allowing
* At the moment of blocking the thread, the function automatically calls lk.lock() (PIMutex::lock()), allowing
* other locked threads to continue.
*
* Once notified or once timeoutMs has passed, the function unblocks and calls lk.unlock() (PIConditionLock::unlock()),
* Once notified or once timeoutMs has passed, the function unblocks and calls lk.unlock() (PIMutex::unlock()),
* leaving lk in the same state as when the function was called. Then the function returns (notice that this last
* mutex locking may block again the thread before returning).
*
@@ -109,7 +108,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(PIConditionLock& lk, int timeoutMs, const std::function<bool()>& condition);
virtual bool waitFor(PIMutex& lk, int timeoutMs, const std::function<bool()>& condition);
private:
PRIVATE_DECLARATION

122
lib/main/thread/pimutex.cpp Normal file
View File

@@ -0,0 +1,122 @@
/*
PIP - Platform Independent Primitives
Mutex
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 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/>.
*/
/** \class PIMutex
* \brief Mutex
* \details
* \section PIMutex_sec0 Synopsis
* %PIMutex provides synchronization blocks between several threads.
* Using mutex guarantees execution of some code only one of threads.
* Mutex contains logic state and functions to change it: \a lock(),
* \a unlock() and \a tryLock().
*
* \section PIMutex_sec1 Usage
* Block of code that should to be executed only one thread simultaniously
* should to be started with \a lock() and ended with \a unlock().
* \snippet pimutex.cpp main
* "mutex" in this example is one for all threads.
*
* */
#include "pimutex.h"
#include "piincludes_p.h"
#ifdef WINDOWS
# include <synchapi.h>
#else
# include <pthread.h>
#endif
PRIVATE_DEFINITION_START(PIMutex)
#ifdef WINDOWS
CRITICAL_SECTION
#else
pthread_mutex_t
#endif
mutex;
PRIVATE_DEFINITION_END(PIMutex)
PIMutex::PIMutex() {
init();
}
PIMutex::~PIMutex() {
destroy();
}
void PIMutex::lock() {
#ifdef WINDOWS
EnterCriticalSection(&(PRIVATE->mutex));
#else
pthread_mutex_lock(&(PRIVATE->mutex));
#endif
}
void PIMutex::unlock() {
#ifdef WINDOWS
LeaveCriticalSection(&(PRIVATE->mutex));
#else
pthread_mutex_unlock(&(PRIVATE->mutex));
#endif
}
bool PIMutex::tryLock() {
bool ret =
#ifdef WINDOWS
(TryEnterCriticalSection(&(PRIVATE->mutex)) != 0);
#else
(pthread_mutex_trylock(&(PRIVATE->mutex)) == 0);
#endif
return ret;
}
void * PIMutex::handle() {
return (void*)&(PRIVATE->mutex);
}
void PIMutex::init() {
#ifdef WINDOWS
InitializeCriticalSection(&(PRIVATE->mutex));
#else
pthread_mutexattr_t attr;
memset(&attr, 0, sizeof(attr));
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
memset(&(PRIVATE->mutex), 0, sizeof(PRIVATE->mutex));
pthread_mutex_init(&(PRIVATE->mutex), &attr);
pthread_mutexattr_destroy(&attr);
#endif
}
void PIMutex::destroy() {
#ifdef WINDOWS
DeleteCriticalSection(&(PRIVATE->mutex));
#else
pthread_mutex_destroy(&(PRIVATE->mutex));
#endif
}

View File

@@ -4,7 +4,7 @@
/*
PIP - Platform Independent Primitives
PIMutexLocker
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
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
@@ -24,6 +24,45 @@
#define PIMUTEX_H
#include "piinit.h"
#include <mutex>
class PIP_EXPORT PIMutex
{
public:
NO_COPY_CLASS(PIMutex)
//! Constructs unlocked mutex
explicit PIMutex();
//! Destroy mutex
~PIMutex();
//! \brief Lock mutex
//! \details If mutex is unlocked it set to locked state and returns immediate.
//! If mutex is already locked function blocks until mutex will be unlocked
void lock();
//! \brief Unlock mutex
//! \details In any case this function returns immediate
void unlock() ;
//! \brief Try to lock mutex
//! \details If mutex is unlocked it set to locked state and returns "true" immediate.
//! If mutex is already locked function returns immediate an returns "false"
bool tryLock();
void * handle();
private:
void init();
void destroy();
PRIVATE_DECLARATION
};
//! \brief PIMutexLocker
//! \details Same as std::lock_guard<std::mutex>.
@@ -40,7 +79,7 @@ public:
~PIMutexLocker() {if (cond) mutex.unlock();}
private:
PIMutex & mutex;
std::atomic_bool cond;
bool cond;
};
#endif // PIMUTEX_H

View File

@@ -25,5 +25,7 @@
#include "pitimer.h"
#include "pipipelinethread.h"
#include "pigrabberbase.h"
#include "pithreadpoolexecutor.h"
#include "piconditionvar.h"
#endif // PITHREADMODULE_H

View File

@@ -0,0 +1,89 @@
/*
PIP - Platform Independent Primitives
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 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 "pithreadpoolexecutor.h"
#include "pisysteminfo.h"
/*! \class PIThreadPoolExecutor
* @brief Thread pools address two different problems: they usually provide improved performance when executing large
* numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and
* managing the resources, including threads, consumed when executing a collection of tasks.
*/
PIThreadPoolExecutor::PIThreadPoolExecutor(size_t corePoolSize, PIBlockingDequeue<std::function<void()> > * taskQueue_) : isShutdown_(false) {
queue_own = false;
if (corePoolSize <= 0)
corePoolSize = PISystemInfo::instance()->processorsCount;
if (!taskQueue_) {
taskQueue = new PIBlockingDequeue<std::function<void()> >();
queue_own = true;
}
for (size_t i = 0; i < corePoolSize; ++i) {
PIThread * thread = new PIThread([&, i](){
auto runnable = taskQueue->poll(100, std::function<void()>());
if (runnable) {
runnable();
}
if (isShutdown_ && taskQueue->size() == 0) threadPool[i]->stop();
});
threadPool.push_back(thread);
thread->start();
}
}
bool PIThreadPoolExecutor::awaitTermination(int timeoutMs) {
PITimeMeasurer measurer;
for (size_t i = 0; i < threadPool.size(); ++i) {
int dif = timeoutMs - (int)measurer.elapsed_m();
if (dif < 0) return false;
if (!threadPool[i]->waitForFinish(dif)) return false;
}
return true;
}
void PIThreadPoolExecutor::shutdownNow() {
isShutdown_ = true;
for (size_t i = 0; i < threadPool.size(); ++i) threadPool[i]->stop();
}
PIThreadPoolExecutor::~PIThreadPoolExecutor() {
shutdownNow();
while (threadPool.size() > 0) delete threadPool.take_back();
if (queue_own)
delete taskQueue;
}
void PIThreadPoolExecutor::execute(const std::function<void()> & runnable) {
if (!isShutdown_) taskQueue->offer(runnable);
}
bool PIThreadPoolExecutor::isShutdown() const {
return isShutdown_;
}
void PIThreadPoolExecutor::shutdown() {
isShutdown_ = true;
}

View File

@@ -17,20 +17,16 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIP_TESTS_EXECUTOR_H
#define PIP_TESTS_EXECUTOR_H
#ifndef PITHREADPOOLEXECUTOR_H
#define PITHREADPOOLEXECUTOR_H
#include "piblockingdequeue.h"
#include <atomic>
/**
* @brief Thread pools address two different problems: they usually provide improved performance when executing large
* numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and
* managing the resources, including threads, consumed when executing a collection of tasks.
*/
class PIThreadPoolExecutor {
public:
explicit PIThreadPoolExecutor(size_t corePoolSize = 1, PIBlockingDequeue<std::function<void()> >* taskQueue_ = new PIBlockingDequeue<std::function<void()> >());
explicit PIThreadPoolExecutor(size_t corePoolSize = -1, PIBlockingDequeue<std::function<void()> > * taskQueue_ = 0);
virtual ~PIThreadPoolExecutor();
@@ -41,7 +37,7 @@ public:
*
* @param runnable not empty function for thread pool execution
*/
void execute(const std::function<void()>& runnable);
void execute(const std::function<void()> & runnable);
void shutdownNow();
@@ -55,10 +51,13 @@ public:
bool isShutdown() const;
bool awaitTermination(int timeoutMs);
private:
std::atomic_bool isShutdown_;
PIBlockingDequeue<std::function<void()> >* taskQueue;
PIBlockingDequeue<std::function<void()> > * taskQueue;
PIVector<PIThread*> threadPool;
bool queue_own;
};
#endif //PIP_TESTS_EXECUTOR_H
#endif // PITHREADPOOLEXECUTOR_H