thread safe getFieldCreate() and getPVDataCreate()

Fully thread safe and ctor order safe on all targets
(not just c++11).  Never destroyed to avoid global
dtor order issues.
This commit is contained in:
Michael Davidsaver
2017-12-28 11:52:12 -06:00
parent 207c24a4fd
commit 43ee4b9cb6
4 changed files with 62 additions and 21 deletions

View File

@@ -19,6 +19,7 @@
#include <sstream>
#include <epicsMutex.h>
#include <epicsThread.h>
#define epicsExportSharedSymbols
#include <pv/reftrack.h>
@@ -1452,18 +1453,33 @@ FieldConstPtr FieldCreate::deserialize(ByteBuffer* buffer, DeserializableControl
}
}
// TODO replace with non-locking singleton pattern
const FieldCreatePtr& FieldCreate::getFieldCreate()
{
static FieldCreatePtr fieldCreate;
static Mutex mutex;
Lock xx(mutex);
if(fieldCreate.get()==0) {
fieldCreate = FieldCreatePtr(new FieldCreate());
namespace detail {
struct field_factory {
FieldCreatePtr fieldCreate;
field_factory() :fieldCreate(new FieldCreate()) {
registerRefCounter("Field", &Field::num_instances);
}
return fieldCreate;
};
}
static detail::field_factory* field_factory_s;
static epicsThreadOnceId field_factory_once = EPICS_THREAD_ONCE_INIT;
static void field_factory_init(void*)
{
try {
field_factory_s = new detail::field_factory;
}catch(std::exception& e){
std::cerr<<"Error initializing getFieldCreate() : "<<e.what()<<"\n";
}
}
const FieldCreatePtr& FieldCreate::getFieldCreate()
{
epicsThreadOnce(&field_factory_once, &field_factory_init, 0);
if(!field_factory_s->fieldCreate)
throw std::logic_error("getFieldCreate() not initialized");
return field_factory_s->fieldCreate;
}
FieldCreate::FieldCreate()

View File

@@ -17,6 +17,7 @@
#include <cstdio>
#include <epicsMutex.h>
#include <epicsThread.h>
#define epicsExportSharedSymbols
#include <pv/lock.h>
@@ -604,19 +605,33 @@ PVUnionPtr PVDataCreate::createPVUnion(PVUnionPtr const & unionToClone)
return punion;
}
// TODO not thread-safe (local static initializers)
// TODO replace with non-locking singleton pattern
namespace detail {
struct pvfield_factory {
PVDataCreatePtr pvDataCreate;
pvfield_factory() :pvDataCreate(new PVDataCreate()) {
registerRefCounter("PVField", &PVField::num_instances);
}
};
}
static detail::pvfield_factory* pvfield_factory_s;
static epicsThreadOnceId pvfield_factory_once = EPICS_THREAD_ONCE_INIT;
static void pvfield_factory_init(void*)
{
try {
pvfield_factory_s = new detail::pvfield_factory;
}catch(std::exception& e){
std::cerr<<"Error initializing getFieldCreate() : "<<e.what()<<"\n";
}
}
const PVDataCreatePtr& PVDataCreate::getPVDataCreate()
{
static PVDataCreatePtr pvDataCreate;
static Mutex mutex;
Lock xx(mutex);
if(pvDataCreate.get()==0) {
registerRefCounter("PVField", &PVField::num_instances);
pvDataCreate = PVDataCreatePtr(new PVDataCreate());
}
return pvDataCreate;
epicsThreadOnce(&pvfield_factory_once, &pvfield_factory_init, 0);
if(!pvfield_factory_s->pvDataCreate)
throw std::logic_error("getPVDataCreate() not initialized");
return pvfield_factory_s->pvDataCreate;
}
// explicitly instanciate to ensure that windows

View File

@@ -1475,11 +1475,16 @@ typedef std::tr1::shared_ptr<PVDoubleArray> PVDoubleArrayPtr;
typedef PVValueArray<std::string> PVStringArray;
typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
namespace detail {
struct pvfield_factory;
}
/**
* @brief This is a singleton class for creating data instances.
*
*/
class epicsShareClass PVDataCreate {
friend struct detail::pvfield_factory;
public:
/**
* get the singleton

View File

@@ -1065,11 +1065,16 @@ private:
const bool createNested; // true - endNested() creates in parent, false - endNested() appends to parent
};
namespace detail {
struct field_factory;
}
/**
* @brief This is a singleton class for creating introspection interfaces.
*
*/
class epicsShareClass FieldCreate {
friend struct detail::field_factory;
public:
static const FieldCreatePtr &getFieldCreate();
/**