Index: /trunk/SophyaLib/HiStats/basedtable.cc
===================================================================
--- /trunk/SophyaLib/HiStats/basedtable.cc	(revision 3391)
+++ /trunk/SophyaLib/HiStats/basedtable.cc	(revision 3392)
@@ -1,9 +1,11 @@
 #include "basedtable.h"
 #include <ctype.h>
-#include "sopnamsp.h"
 #include "pexceptions.h"
+#include "thsafeop.h"
+
+namespace SOPHYA {
 
 /*!
-   \class SOPHYA::DataTableRow
+   \class DataTableRow
    \ingroup HiStats
    This class is intented to be used with datatable classes
@@ -58,8 +60,11 @@
 
 /*!
-   \class SOPHYA::BaseDataTable
+   \class BaseDataTable
    \ingroup HiStats
    Base class for data tables. Each line represent a record
    and the column contains a given data type.
+   \warning 
+   Thread safe fill operation can be activated using the method SetThreadSafe()
+   Default mode is NON thread-safe fill.   
 */
 
@@ -147,4 +152,5 @@
   mVarMTV = NULL;
   mInfo = NULL;
+  mThS = NULL;
 }
 
@@ -154,5 +160,61 @@
   if (mVarMTV) delete[] mVarMTV;
   if (mInfo) delete mInfo;
-}
+  if (mThS) delete mThS;
+}
+
+/*!
+  \brief Activate or deactivate thread-safe \b AddRow() operations
+
+  If fg==true, create an ThSafeOp object in order to insure atomic AddRow()
+  and GetRow()/GetColumn() operations. if fg==false, the ThSafeOp object (mThS) 
+  of the target DataTable is destroyed.
+
+  When activated, the following operations are thread-safe : 
+
+  - AddRow(const r_8* data)
+  - AddRow(const MuTyV* data)
+  - AddRow(DataTableRow const& data)
+  - GetRow(sa_size_t n, DataTableRow& row)
+  - GetRow(sa_size_t n, MuTyV* mtvp)
+  - GetColumnD(sa_size_t k)
+
+  \warning The default AddRow() operation mode for DataTables is NOT thread-safe. 
+  Please note also that the thread-safety state is NOt saved to PPF (or FITS) streams.
+*/
+void BaseDataTable::SetThreadSafe(bool fg) 
+{
+  if (fg) {
+    if (mThS) return;
+    else mThS = new ThSafeOp();
+  }
+  else {
+    if (mThS) delete mThS;
+    mThS = NULL;
+  }
+}
+
+
+/*! \cond
+  \class DT_TSOP_SYNC 
+  \ingroup HiStats 
+  Classe utilitaire pour faciliter la gestion de lock pour 
+  operations thread-safe BaseDataTable
+*/
+class DT_TSOP_SYNC {
+ public:
+  explicit DT_TSOP_SYNC(ThSafeOp* ths) 
+  { 
+    ths_ = ths; 
+    if (ths_) ths_->lock(); 
+  }
+  ~DT_TSOP_SYNC() 
+  {
+    if (ths_) ths_->unlock(); 
+  }
+  inline ThSafeOp* NOp() { return ths_; }
+ protected:
+  ThSafeOp* ths_;
+};
+/*! \endcond */
 
 sa_size_t BaseDataTable::CopyStructure(BaseDataTable const & a)
@@ -273,4 +335,6 @@
 sa_size_t BaseDataTable::AddRow(const r_8* data)
 {
+  DT_TSOP_SYNC dttss(mThS); dttss.NOp();  // Thread-safe operation 
+
   if (NVar() == 0) 
     throw ParmError("BaseDataTable::AddRow(const r_8*) Table has no column !");
@@ -309,4 +373,6 @@
 sa_size_t BaseDataTable::AddRow(const MuTyV* data)
 {
+  DT_TSOP_SYNC dttss(mThS); dttss.NOp();  // Thread-safe operation 
+
   if (NVar() == 0) 
     throw ParmError("BaseDataTable::AddRow(const MuTyV*) Table has no column !");
@@ -379,5 +445,4 @@
   Return a reference to the input \b row object. 
   Generate an exception if the input \b row object has the wrong size.
-  This method is slower(less efficient) than the GetRow(n) method.
 */
 DataTableRow& BaseDataTable::GetRow(sa_size_t n, DataTableRow& row) const
@@ -385,37 +450,42 @@
   if ( row.Size() != NCols() )
     throw SzMismatchError(" BaseDataTable::GetRow(n, row) - row.Size() != NCols() ");
-  MuTyV* rmtv = GetRow(n);
-  for(sa_size_t k=0; k<NCols(); k++)
-    row[k] = rmtv[k];
+  GetRow(n, row.MTVPtr());
   return row;
 }
 
-MuTyV* BaseDataTable::GetRow(sa_size_t n) const 
-{
+/*!
+  For thread-safe operation, specify a valid \b mtvp  pointer (!= NULL)  
+*/
+MuTyV* BaseDataTable::GetRow(sa_size_t n, MuTyV* mtvp) const 
+{
+  DT_TSOP_SYNC dttss(mThS); dttss.NOp();  // Thread-safe operation 
+
   if ((n < 0) || (n >= NEntry())) 
     throw RangeCheckError("BaseDataTable::GetRow() out of range line index n");
-  if (mVarMTV == NULL) mVarMTV = new MuTyV[NVar()];
-
+  if (mtvp == NULL) {
+    if (mVarMTV == NULL) mVarMTV = new MuTyV[NVar()];
+    mtvp = mVarMTV;
+  }
   sa_size_t bid = n/mSegSz;
   sa_size_t off = n%mSegSz;
   for(sa_size_t k=0; k<mIColsP.size(); k++) 
-    mVarMTV[mIColIdx[k]] = mIColsP[k]->GetCstSegment(bid)[off];
+    mtvp[mIColIdx[k]] = mIColsP[k]->GetCstSegment(bid)[off];
   for(sa_size_t k=0; k<mLColsP.size(); k++) 
-    mVarMTV[mLColIdx[k]] = mLColsP[k]->GetCstSegment(bid)[off];
+    mtvp[mLColIdx[k]] = mLColsP[k]->GetCstSegment(bid)[off];
   for(sa_size_t k=0; k<mFColsP.size(); k++) 
-    mVarMTV[mFColIdx[k]] = mFColsP[k]->GetCstSegment(bid)[off];
+    mtvp[mFColIdx[k]] = mFColsP[k]->GetCstSegment(bid)[off];
   for(sa_size_t k=0; k<mDColsP.size(); k++) {
     if (GetColumType(mDColIdx[k]) == DateTimeField) 
-      mVarMTV[mDColIdx[k]] = TimeStamp(mDColsP[k]->GetCstSegment(bid)[off]);
-    else mVarMTV[mDColIdx[k]] = mDColsP[k]->GetCstSegment(bid)[off];
+      mtvp[mDColIdx[k]] = TimeStamp(mDColsP[k]->GetCstSegment(bid)[off]);
+    else mtvp[mDColIdx[k]] = mDColsP[k]->GetCstSegment(bid)[off];
   }
   for(sa_size_t k=0; k<mYColsP.size(); k++) 
-    mVarMTV[mYColIdx[k]] = mYColsP[k]->GetCstSegment(bid)[off];
+    mtvp[mYColIdx[k]] = mYColsP[k]->GetCstSegment(bid)[off];
   for(sa_size_t k=0; k<mZColsP.size(); k++) 
-    mVarMTV[mZColIdx[k]] = mZColsP[k]->GetCstSegment(bid)[off];
+    mtvp[mZColIdx[k]] = mZColsP[k]->GetCstSegment(bid)[off];
   for(sa_size_t k=0; k<mSColsP.size(); k++) 
-    mVarMTV[mSColIdx[k]] = mSColsP[k]->GetCstSegment(bid)[off];
-
-  return mVarMTV;
+    mtvp[mSColIdx[k]] = mSColsP[k]->GetCstSegment(bid)[off];
+
+  return mtvp;
 }
 
@@ -424,4 +494,6 @@
 TVector<r_8> BaseDataTable::GetColumnD(sa_size_t k) const
 {
+  DT_TSOP_SYNC dttss(mThS); dttss.NOp();  // Thread-safe operation 
+
   if ((k < 0) || (k >= NVar())) 
     throw RangeCheckError("BaseDataTable::GetColumnD() out of range column index k");
@@ -968,2 +1040,4 @@
 }
 
+} // FIN namespace SOPHYA 
+
Index: /trunk/SophyaLib/HiStats/basedtable.h
===================================================================
--- /trunk/SophyaLib/HiStats/basedtable.h	(revision 3391)
+++ /trunk/SophyaLib/HiStats/basedtable.h	(revision 3392)
@@ -63,4 +63,7 @@
   {  row.Print(s);  return(s);  }
 
+//  Forward class declaration for Thread-safe operations
+class ThSafeOp;
+
 //! Interface definition for classes handling data in a table.
 class BaseDataTable : public AnyDataObj , public NTupleInterface {
@@ -81,4 +84,9 @@
   BaseDataTable(sa_size_t segsz=512);
   virtual           ~BaseDataTable();
+
+  // Activate/deactivate thread-safe AddRow()/GetRow() operation
+  virtual void      SetThreadSafe(bool fg=true);
+  //! Return true if AddRow()/GetRow()  operations are thread-safe
+  inline bool       IsThreadSafe() const { return ((mThS)?true:false); }
   
   //! Adds a column holding integer, named \b cnom
@@ -193,5 +201,5 @@
   virtual DataTableRow&   GetRow(sa_size_t n, DataTableRow& row) const ;
   //! Return the information stored in line (row) \b n of the table 
-  virtual MuTyV *   GetRow(sa_size_t n) const ;
+  virtual MuTyV *   GetRow(sa_size_t n, MuTyV* mtvp=NULL) const ;
   //! Return the information stored in line \b n of the table. Alias of GetLine 
   inline  MuTyV *   GetLine(sa_size_t n) const 
@@ -316,4 +324,6 @@
   std::vector< SegDBInterface<string> * > mSColsP; 
   std::vector< sa_size_t > mSColIdx;
+
+  ThSafeOp* mThS;       // != NULL -> Thread safe operations
   
 }; 
Index: /trunk/SophyaLib/HiStats/datatable.cc
===================================================================
--- /trunk/SophyaLib/HiStats/datatable.cc	(revision 3391)
+++ /trunk/SophyaLib/HiStats/datatable.cc	(revision 3392)
@@ -1,11 +1,12 @@
 #include "datatable.h"
-#include "sopnamsp.h"
 #include "strutil.h"
 #include "pexceptions.h"
 #include "fiosegdb.h"
-
+#include "thsafeop.h"
+
+namespace SOPHYA { 
 
 /*!
-   \class SOPHYA::DataTable
+   \class DataTable
    \ingroup HiStats
    This class can be used to organize data in table (row-column) form.
@@ -61,4 +62,5 @@
   The copy constructur shares the data if \b share=true. 
   Otherwise, the Clone() method is called to make a complete copy.
+  This constructor copies also the thread safety state from \b a .
 */
 DataTable::DataTable(DataTable const & a, bool share)
@@ -71,9 +73,14 @@
   if (a.mInfo)  mInfo = new DVList(*(a.mInfo));
 }
-//! Copy the table structure from \b a and shares the data (columns content)
+/*! 
+  Copy the table structure from \b a and shares the data (columns content).
+  The tread-safety state is copied from \b a .
+*/
 void DataTable::Share(DataTable const & a)
 {
   // On copie la structure de table 
   CopyStructure(a);
+  if (a.IsThreadSafe())  SetThreadSafe(true);
+  else SetThreadSafe(false);
   // Et on partage les donnees des colonnes 
   for (size_t kk=0; kk<mNames.size(); kk++) {
@@ -115,5 +122,7 @@
   // On copie la structure de table 
   CopyStructure(a);
-  // Et on partage les donnees des colonnes 
+  if (a.IsThreadSafe())  SetThreadSafe(true);
+  else SetThreadSafe(false);
+  // Et on copie les donnees des colonnes 
   for (size_t kk=0; kk<mNames.size(); kk++) {
     sa_size_t sk = mNames[kk].ser;
@@ -161,4 +170,6 @@
   if (mInfo) delete mInfo;
   mInfo = NULL;
+  if (mThS) delete mThS;
+  mThS = NULL;
   mMin.clear();
   mMax.clear();
@@ -278,2 +289,3 @@
 }
 
+} // FIN namespace SOPHYA 
Index: /trunk/SophyaLib/HiStats/ntuple.cc
===================================================================
--- /trunk/SophyaLib/HiStats/ntuple.cc	(revision 3391)
+++ /trunk/SophyaLib/HiStats/ntuple.cc	(revision 3392)
@@ -5,4 +5,5 @@
 #include "perrors.h"
 #include "ntuple.h"
+#include "thsafeop.h"
 
 namespace SOPHYA {
@@ -17,4 +18,7 @@
    Simple NTuple class (a Table or 2-D data set) with double or 
    single precision floating point value columns. 
+   \warning 
+   Thread safe fill operation can be activated using the method SetThreadSafe()
+   Default mode is NON thread-safe fill.
    \sa SOPHYA::ObjFileIO<NTuple>
 
@@ -65,4 +69,5 @@
 mFgDouble = true;
 mInfo = NULL;
+mThS = NULL; 
 }
 
@@ -89,4 +94,5 @@
 mVarD = NULL;
 mInfo = NULL;
+mThS = NULL; 
 if (nvar <= 0)  throw ParmError("NTuple::NTuple(nvar<=0) "); 
 mNVar = nvar;
@@ -126,4 +132,5 @@
 mVarD = NULL;
 mInfo = NULL;
+mThS = NULL; 
 int nvar = noms.size();
 if (nvar <= 0)  throw ParmError("NTuple::NTuple(nvar<=0) "); 
@@ -150,5 +157,8 @@
 }
 
-//! Copy constructor - Copies the table definition and associated data 
+/*! 
+  Copy constructor - Copies the table definition and associated data, 
+  as well as the tread safety state
+*/
 //                                       cmv 8/10/99
 //++
@@ -158,5 +168,5 @@
 //--
 : mNVar(0), mNEnt(0), mBlk(0), mNBlk(0)
-, mVar(NULL), mVarD(NULL), mInfo(NULL)
+ , mVar(NULL), mVarD(NULL), mInfo(NULL),mThS(NULL)
 {
 if(NT.mNVar<=0) return; // cas ou NT est cree par defaut
@@ -185,31 +195,34 @@
 
 if(NT.mInfo!=NULL) {mInfo = new DVList; *mInfo = *(NT.mInfo);}
-
+mThS = NULL; 
+if(NT.mThS!=NULL) SetThreadSafe(true);
 return;
 }
 
-/* --Methode-- 
-//! Constructor with table initialized from a PPF file
-//++
-NTuple::NTuple(char *flnm)
-//
-//	Createur lecture fichier ppersist.
-//--
-{
-mNVar = mNEnt = mBlk = mNBlk = 0;
-mVar = NULL;
-mVarD = NULL;
-mNames = NULL;
-mInfo = NULL;
-PInPersist s(flnm);
-ObjFileIO<NTuple> fiont(this);
-fiont.Read(s);
-}
+
+/* --Methode-- */
+NTuple::~NTuple()
+{
+Clean();
+}
+/* --Methode-- */ 
+/*!
+  \brief Activate or deactivate thread-safe \b Fill() operations
+  If fg==true, create an ThSafeOp object in order to insure atomic Fill()
+  operations. if fg==false, the ThSafeOp object (mThS) of the target NTuple
+  is destroyed. 
+  \warning The default Fill() operation mode for NTuples is NOT thread-safe. 
+  Please note also that the thread-safety state is NOt saved to PPF (or FITS) streams.
 */
-
-/* --Methode-- */
-NTuple::~NTuple()
-{
-Clean();
+void NTuple::SetThreadSafe(bool fg) 
+{
+if (fg) {
+  if (mThS) return;
+  else mThS = new ThSafeOp();
+}
+else {
+  if (mThS) delete mThS;
+  mThS = NULL;
+}
 }
 
@@ -221,4 +234,5 @@
 if (mVarD) delete[] mVarD;
 if (mInfo) delete mInfo;
+if (mThS) delete mThS;
 int i;
 if(mNBlk>0) { 
@@ -232,4 +246,5 @@
 mVarD = NULL;
 mInfo = NULL;
+mThS = NULL;
 return;
 }
@@ -283,4 +298,5 @@
 //--
 {
+if (mThS)  mThS->lock();   // Thread-safe operation 
 int numb = mNEnt/mBlk;
 if (numb >= mNBlk) {
@@ -302,4 +318,5 @@
 else memcpy((mPtr[numb]+offb*mNVar), x, mNVar*sizeof(r_4));
 mNEnt++;
+if (mThS)  mThS->unlock();   // Thread-safe operation 
 return;
 }
@@ -316,4 +333,5 @@
 //--
 {
+if (mThS)  mThS->lock();   // Thread-safe operation 
 int numb = mNEnt/mBlk;
 if (numb >= mNBlk) {
@@ -337,4 +355,5 @@
 
 mNEnt++;
+if (mThS)  mThS->unlock();   // Thread-safe operation 
 return;
 }
Index: /trunk/SophyaLib/HiStats/ntuple.h
===================================================================
--- /trunk/SophyaLib/HiStats/ntuple.h	(revision 3391)
+++ /trunk/SophyaLib/HiStats/ntuple.h	(revision 3392)
@@ -21,4 +21,6 @@
 //  Forward class declaration for Fits handler
 class FITS_NTuple;
+//  Forward class declaration for Thread-safe operations
+class ThSafeOp;
 
 //! Class for creation and management of double or float data sets in a table
@@ -31,4 +33,9 @@
   NTuple(const NTuple& NT);
   virtual ~NTuple();
+
+  // Activate/deactivate thread-safe Fill operation
+  void SetThreadSafe(bool fg=true);
+  //! Return true if Fill  operations are thread-safe
+  inline bool IsThreadSafe() const { return ((mThS)?true:false); }
 
   NTuple& operator = (const NTuple& NT);
@@ -102,4 +109,5 @@
   DVList* mInfo;        // Infos (variables) attachees au NTuple
   
+  ThSafeOp* mThS;       // != NULL -> Thread safe operations
 };
 
Index: /trunk/SophyaLib/HiStats/swppfdtable.cc
===================================================================
--- /trunk/SophyaLib/HiStats/swppfdtable.cc	(revision 3391)
+++ /trunk/SophyaLib/HiStats/swppfdtable.cc	(revision 3392)
@@ -1,9 +1,10 @@
 #include "swppfdtable.h"
-#include "sopnamsp.h"
 #include "pexceptions.h"
-
+#include "thsafeop.h"
+
+namespace SOPHYA { 
 
 /*!
-   \class SOPHYA::SwPPFDataTable
+   \class SwPPFDataTable
    \ingroup HiStats
    This class can be used to organize data in table (row-column) form.
@@ -96,5 +97,6 @@
 }
 
-//! copy constructor - shares the data
+//! copy constructor - shares the data (and copies the thread safety state)
+
 SwPPFDataTable::SwPPFDataTable(SwPPFDataTable const & a)
   : BaseDataTable(a.SegmentSize()),
@@ -137,4 +139,6 @@
   // On copie la structure de table 
   CopyStructure(a);
+  if (a.IsThreadSafe())  SetThreadSafe(true);
+  else SetThreadSafe(false);
 
   //
@@ -229,4 +233,6 @@
   if (mInfo) delete mInfo;
   mInfo = NULL;
+  if (mThS) delete mThS;
+  mThS = NULL;
   mMin.clear();
   mMax.clear();
@@ -355,4 +361,5 @@
   // On est oblige de calculer les min-max lors du remplissage
   // On ne peut pas en effet 'relire' le swap pendant l'ecriture
+  if (mThS) mThS->lock();   // tread-safety
   for(sa_size_t k=0; k<NVar(); k++) {
     double x = data[k];
@@ -361,4 +368,5 @@
     mMinMaxNEnt[k]++;
   }
+  if (mThS) mThS->unlock(); // tread-safety
   return BaseDataTable::AddRow(data);
 }
@@ -373,4 +381,5 @@
   // On est oblige de calculer les min-max lors du remplissage
   // On ne peut pas en effet 'relire' le swap pendant l'ecriture
+  if (mThS) mThS->lock();   // tread-safety
   for(sa_size_t k=0; k<NVar(); k++) {
     double x = (double)data[k];
@@ -379,4 +388,5 @@
     mMinMaxNEnt[k]++;
   }
+  if (mThS) mThS->unlock(); // tread-safety
   return BaseDataTable::AddRow(data);
 }
@@ -394,2 +404,4 @@
   return AddRow(data.MTVPtr());
 }
+
+} // FIN namespace SOPHYA 
