Commit 3be517fb authored by Pavel Vainerman's avatar Pavel Vainerman

(IOController, IONotifyController): рефакторинг работы с userdata,

а также попытка оптимизировать работу с mutex-ами в INC, правки комментариев.
parent 3338255d
......@@ -762,15 +762,10 @@ namespace uniset
if( hist.empty() )
return;
if( usi->userdata[udataHistory] == nullptr )
HistoryItList* lst = static_cast<HistoryItList*>(usi->getUserData(udataHistory));
if( !lst )
return;
HistoryItList& lst = *(static_cast<HistoryItList*>(usi->userdata[udataHistory]));
// auto i = histmap.find(s_it->si.id);
// if( i == histmap.end() )
// return;
long value = 0;
unsigned long sm_tv_sec = 0;
unsigned long sm_tv_nsec = 0;
......@@ -786,7 +781,7 @@ namespace uniset
<< " value=" << value
<< endl;
for( auto && it1 : lst)
for( auto&& it1 : (*lst) )
{
History::iterator it = it1;
......
......@@ -33,7 +33,15 @@
//---------------------------------------------------------------------------
namespace uniset
{
/*! Реализация интерфейса IOController-а */
/*! Реализация интерфейса IOController-а
* Важной особенностью данной реализации является то, что
* список входов/выходов (ioList) формируется один раз во время создания объекта
* и не меняется (!) в процессе работы. На этом построены некоторые оптимизации!
* Поэтому неизменность ioList во время всей жизни объекта должна гарантироваться.
* В частности, очень важной является структура USensorInfo, а также userdata,
* которые используются для "кэширования" (сохранения) указателей на специальные данные.
* (см. также IONotifyContoller).
*/
class IOController:
public UniSetManager,
public POA_IOController_i
......@@ -298,8 +306,13 @@ namespace uniset
// Дополнительные (вспомогательные поля)
uniset::uniset_rwmutex val_lock; /*!< флаг блокирующий работу со значением */
// userdata (универасльный, небезопасный способ расширения информации связанной с датчиком)
static const size_t MaxUserData = 4;
void* userdata[MaxUserData] = { nullptr, nullptr, nullptr, nullptr }; /*!< расширение для возможности хранения своей информации */
uniset::uniset_rwmutex userdata_lock; /*!< mutex для работы с userdata */
void* getUserData( size_t index );
void setUserData( size_t index, void* data );
// сигнал для реализации механизма зависимостией..
// (все зависимые датчики подключаются к нему (см. NCRestorer::init_depends_signals)
......@@ -328,7 +341,7 @@ namespace uniset
return std::move(s);
}
inline uniset::SensorMessage makeSensorMessage()
inline uniset::SensorMessage makeSensorMessage( bool with_lock = false )
{
uniset::SensorMessage sm;
sm.id = si.id;
......@@ -337,6 +350,7 @@ namespace uniset
sm.priority = (uniset::Message::Priority)priority;
// лочим только изменяемые поля
if( with_lock )
{
uniset::uniset_rwmutex_rlock lock(val_lock);
sm.value = value;
......@@ -346,6 +360,15 @@ namespace uniset
sm.supplier = supplier;
sm.undefined = undefined;
}
else
{
sm.value = value;
sm.sm_tv.tv_sec = tv_sec;
sm.sm_tv.tv_nsec = tv_nsec;
sm.ci = ci;
sm.supplier = supplier;
sm.undefined = undefined;
}
return std::move(sm);
}
......
......@@ -111,23 +111,25 @@ namespace uniset
\note Следует иметь ввиду, что для \b ЗАВИСИМОГО датчика функция setValue(..) действует как обычно и
даже если он "заблокирован", значение в него можно сохранять. Оно "появиться" как только сниметься блокировка.
\section sec_NC_Optimization Оптимизация работы со списком "заказчиков"
Для оптимизации поиска списка заказчиков для конкретного датчика используется поле userdata (void*) у USensorInfo!
Это опасный и "некрасивый" хак, но который позволяет избавиться от одного лишнего поиска по unordered_map<SensorID,ConsumerList>.
Суть в том что к датчику через usedata мы привязываем указатель на список заказчиков. Сделано через userdata,
т.к. сам map "хранится" в IOController и IONotifyController не может поменять тип (в текущей реализации по крайней мере).
В userdata задействованы два места (см. UserDataID) для списка заказчиков и для списка порогов.
\section sec_NC_Optimization Оптимизация работы со списком "заказчиков"
Для оптимизации поиска списка заказчиков для конкретного датчика используется поле userdata (void*) у USensorInfo!
Это опасный и "некрасивый" хак, но он позволяет избавиться от одного лишнего поиска по unordered_map<SensorID,ConsumerList>.
Суть в том что к датчику через usedata мы привязываем указатель на список заказчиков. Сделано через userdata,
т.к. сам map "хранится" в IOController и IONotifyController не может поменять тип (в текущей реализации по крайней мере).
В userdata задействованы два места (см. UserDataID) для списка заказчиков и для списка порогов.
ри этом, чтобы гарантировать корректность работы, cписки заказчиков по тому или иному датчику,
создаются (см. функцию ask()), но никогда не удаляются, даже если остаются пустыми.
Это сделано, чтобы сохранённые указатели в userdata, оставались всегда валидными
(т.к. используются из разных потоков).
*/
//---------------------------------------------------------------------------
/*! \class IONotifyController
\section AskSensors Заказ датчиков
....
ConsumerMaxAttempts - максимальное число неудачных
попыток послать сообщение "заказчику". Настраивается в
конфигурационном файле. По умолчанию = 5.
*/
*
* \section AskSensors Заказ датчиков
* ....
* \b ConsumerMaxAttempts - максимальное число неудачных попыток послать сообщение "заказчику".
* Настраивается в конфигурационном файле. По умолчанию = 5.
*/
class IONotifyController:
public IOController,
public POA_IONotifyController_i
......@@ -179,7 +181,7 @@ namespace uniset
ref(ref), attempt(maxAttemtps) {}
UniSetObject_i_var ref;
size_t attempt;
size_t attempt = { 10 };
size_t lostEvents = { 0 }; // количество потерянных сообщений (не смогли послать)
size_t smCount = { 0 }; // количество посланных SensorMessage
......@@ -283,7 +285,7 @@ namespace uniset
protected:
IONotifyController();
virtual bool activateObject() override;
virtual void initItem(std::shared_ptr<USensorInfo>& usi, IOController* ic );
virtual void initItem( std::shared_ptr<USensorInfo>& usi, IOController* ic );
//! посылка информации об изменении состояния датчика (всем или указанному заказчику)
virtual void send( ConsumerListInfo& lst, const uniset::SensorMessage& sm, const uniset::ConsumerInfo* ci = nullptr );
......@@ -351,6 +353,7 @@ namespace uniset
/*! добавить новый порог для датчика */
bool addThreshold(ThresholdExtList& lst, ThresholdInfoExt&& ti, const uniset::ConsumerInfo& ci);
/*! удалить порог для датчика */
bool removeThreshold(ThresholdExtList& lst, ThresholdInfoExt& ti, const uniset::ConsumerInfo& ci);
......@@ -380,8 +383,6 @@ namespace uniset
/*! map для хранения информации о заказчиках с которыми была потеряна связь
* и которые были удалены из списка заказчиков
* size_t - количество раз
* ObjectId - id заказчика
*/
std::unordered_map<uniset::ObjectId, LostConsumerInfo> lostConsumers;
};
......
......@@ -620,7 +620,25 @@ IOController::USensorInfo::operator=(IOController_i::SensorIOInfo* r)
(*this) = (*r);
return *this;
}
// ----------------------------------------------------------------------------------------
void* IOController::USensorInfo::getUserData( size_t index )
{
if( index > MaxUserData )
return nullptr;
uniset::uniset_rwmutex_rlock ulock(userdata_lock);
return userdata[index];
}
void IOController::USensorInfo::setUserData( size_t index, void* data )
{
if( index > MaxUserData )
return;
uniset::uniset_rwmutex_wrlock ulock(userdata_lock);
userdata[index] = data;
}
// ----------------------------------------------------------------------------------------
const IOController::USensorInfo&
IOController::USensorInfo::operator=(const IOController_i::SensorIOInfo& r)
{
......@@ -628,7 +646,7 @@ IOController::USensorInfo::operator=(const IOController_i::SensorIOInfo& r)
// any=0;
return *this;
}
// ----------------------------------------------------------------------------------------
void IOController::USensorInfo::init( const IOController_i::SensorIOInfo& s )
{
IOController::USensorInfo r(s);
......
......@@ -75,7 +75,7 @@ void NCRestorer::addlist( IONotifyController* ic, std::shared_ptr<IOController::
case UniversalIO::AO:
{
ic->askIOList[inf->si.id] = std::move(lst);
inf->userdata[IONotifyController::udataConsumerList] = &(ic->askIOList[inf->si.id]);
inf->setUserData(IONotifyController::udataConsumerList, &(ic->askIOList[inf->si.id]) );
break;
}
......@@ -151,29 +151,15 @@ NCRestorer::SInfo& NCRestorer::SInfo::operator=( const IOController_i::SensorIOI
this->blocked = inf.blocked;
this->dbignore = inf.dbignore;
for( size_t i = 0; i < IOController::USensorInfo::MaxUserData; i++ )
this->userdata[i] = nullptr;
{
uniset_rwmutex_wrlock l(this->userdata_lock);
for( size_t i = 0; i < IOController::USensorInfo::MaxUserData; i++ )
this->userdata[i] = nullptr;
}
return *this;
}
// ------------------------------------------------------------------------------------------
#if 0
NCRestorer::SInfo& NCRestorer::SInfo::operator=( const std::shared_ptr<IOController_i::SensorIOInfo>& inf )
{
this->si = inf->si;
this->type = inf->type;
this->priority = inf->priority;
this->default_val = inf->default_val;
this->real_value = inf->real_value;
this->ci = inf->ci;
this->undefined = inf->undefined;
this->blocked = inf->blocked;
this->dbignore = inf->dbignore;
this->any = 0;
return *this;
}
#endif
// ------------------------------------------------------------------------------------------
void NCRestorer::init_depends_signals( IONotifyController* ic )
{
for( auto it = ic->ioList.begin(); it != ic->ioList.end(); ++it )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment