Commit 6c3be247 authored by Chris Cantwell's avatar Chris Cantwell

Merge branch 'feature/threading' into 'master'

Feature/threading

Adding the threading routines; no code uses this yet.

See merge request !463
parents c9fdad4b af4b5463
...@@ -111,7 +111,8 @@ OperatorFactory& GetOperatorFactory() ...@@ -111,7 +111,8 @@ OperatorFactory& GetOperatorFactory()
{ {
typedef Loki::SingletonHolder<OperatorFactory, typedef Loki::SingletonHolder<OperatorFactory,
Loki::CreateUsingNew, Loki::CreateUsingNew,
Loki::NoDestroy > Type; Loki::NoDestroy,
Loki::SingleThreaded> Type;
return Type::Instance(); return Type::Instance();
} }
......
...@@ -66,7 +66,8 @@ namespace Nektar ...@@ -66,7 +66,8 @@ namespace Nektar
{ {
typedef Loki::SingletonHolder<MeshPartitionFactory, typedef Loki::SingletonHolder<MeshPartitionFactory,
Loki::CreateUsingNew, Loki::CreateUsingNew,
Loki::NoDestroy > Type; Loki::NoDestroy,
Loki::SingleThreaded> Type;
return Type::Instance(); return Type::Instance();
} }
......
...@@ -43,6 +43,8 @@ ...@@ -43,6 +43,8 @@
#include <boost/preprocessor/arithmetic/sub.hpp> #include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp> #include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/iteration/iterate.hpp> #include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
...@@ -65,6 +67,8 @@ namespace Nektar ...@@ -65,6 +67,8 @@ namespace Nektar
// Generate parameter typenames with default type of 'none' // Generate parameter typenames with default type of 'none'
#define FACTORY_print(z, n, data) BOOST_PP_CAT(data, n) = none #define FACTORY_print(z, n, data) BOOST_PP_CAT(data, n) = none
typedef boost::unique_lock<boost::shared_mutex> WriteLock;
typedef boost::shared_lock<boost::shared_mutex> ReadLock;
/** /**
* @class NekFactory * @class NekFactory
...@@ -144,7 +148,7 @@ namespace Nektar ...@@ -144,7 +148,7 @@ namespace Nektar
public: public:
NekFactory() {} NekFactory() : m_mutex() {}
/** /**
* @brief Create an instance of the class referred to by \c idKey. * @brief Create an instance of the class referred to by \c idKey.
...@@ -158,6 +162,9 @@ namespace Nektar ...@@ -158,6 +162,9 @@ namespace Nektar
tBaseSharedPtr CreateInstance(tKey idKey BOOST_PP_COMMA_IF(MAX_PARAM) tBaseSharedPtr CreateInstance(tKey idKey BOOST_PP_COMMA_IF(MAX_PARAM)
BOOST_PP_ENUM_BINARY_PARAMS(MAX_PARAM, tParam, x)) BOOST_PP_ENUM_BINARY_PARAMS(MAX_PARAM, tParam, x))
{ {
ReadLock vReadLock(m_mutex);
// Now try and find the key in the map. // Now try and find the key in the map.
TMapFactoryIterator it = getMapFactory()->find(idKey); TMapFactoryIterator it = getMapFactory()->find(idKey);
...@@ -165,11 +172,14 @@ namespace Nektar ...@@ -165,11 +172,14 @@ namespace Nektar
// create a new instance of the class. // create a new instance of the class.
if (it != getMapFactory()->end()) if (it != getMapFactory()->end())
{ {
if (it->second.m_func) ModuleEntry *tmp = &(it->second);
vReadLock.unlock();
if (tmp->m_func)
{ {
try try
{ {
return it->second.m_func(BOOST_PP_ENUM_PARAMS(MAX_PARAM, x)); return tmp->m_func(BOOST_PP_ENUM_PARAMS(MAX_PARAM, x));
} }
catch (const std::string& s) catch (const std::string& s)
{ {
...@@ -205,6 +215,8 @@ namespace Nektar ...@@ -205,6 +215,8 @@ namespace Nektar
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator,
tDescription pDesc = "") tDescription pDesc = "")
{ {
WriteLock vWriteLock(m_mutex);
ModuleEntry e(classCreator, pDesc); ModuleEntry e(classCreator, pDesc);
getMapFactory()->insert(std::pair<tKey,ModuleEntry>(idKey, e)); getMapFactory()->insert(std::pair<tKey,ModuleEntry>(idKey, e));
return idKey; return idKey;
...@@ -216,6 +228,8 @@ namespace Nektar ...@@ -216,6 +228,8 @@ namespace Nektar
*/ */
bool ModuleExists(tKey idKey) bool ModuleExists(tKey idKey)
{ {
ReadLock vReadLock(m_mutex);
// Now try and find the key in the map. // Now try and find the key in the map.
TMapFactoryIterator it = getMapFactory()->find(idKey); TMapFactoryIterator it = getMapFactory()->find(idKey);
...@@ -232,6 +246,8 @@ namespace Nektar ...@@ -232,6 +246,8 @@ namespace Nektar
*/ */
void PrintAvailableClasses(std::ostream& pOut = std::cout) void PrintAvailableClasses(std::ostream& pOut = std::cout)
{ {
ReadLock vReadLock(m_mutex);
pOut << std::endl << "Available classes: " << std::endl; pOut << std::endl << "Available classes: " << std::endl;
TMapFactoryIterator it; TMapFactoryIterator it;
for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it) for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
...@@ -260,6 +276,8 @@ namespace Nektar ...@@ -260,6 +276,8 @@ namespace Nektar
*/ */
tKey GetKey(tDescription pDesc) tKey GetKey(tDescription pDesc)
{ {
ReadLock vReadLock(m_mutex);
TMapFactoryIterator it; TMapFactoryIterator it;
for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it) for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
{ {
...@@ -280,6 +298,8 @@ namespace Nektar ...@@ -280,6 +298,8 @@ namespace Nektar
*/ */
std::string GetClassDescription(tKey idKey) std::string GetClassDescription(tKey idKey)
{ {
ReadLock vReadLock(m_mutex);
// Now try and find the key in the map. // Now try and find the key in the map.
TMapFactoryIterator it = getMapFactory()->find(idKey); TMapFactoryIterator it = getMapFactory()->find(idKey);
...@@ -305,6 +325,8 @@ namespace Nektar ...@@ -305,6 +325,8 @@ namespace Nektar
TMapFactory mMapFactory; TMapFactory mMapFactory;
boost::shared_mutex m_mutex;
}; };
#undef FACTORY_print #undef FACTORY_print
...@@ -325,6 +347,11 @@ namespace Nektar ...@@ -325,6 +347,11 @@ namespace Nektar
#define n BOOST_PP_ITERATION() #define n BOOST_PP_ITERATION()
// Define macro for printing the non-required template parameters // Define macro for printing the non-required template parameters
#define FACTORY_print(z, n, data) data #define FACTORY_print(z, n, data) data
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/locks.hpp>
typedef boost::unique_lock<boost::shared_mutex> WriteLock;
typedef boost::shared_lock<boost::shared_mutex> ReadLock;
template < typename tKey, template < typename tKey,
typename tBase BOOST_PP_COMMA_IF(n) typename tBase BOOST_PP_COMMA_IF(n)
...@@ -352,19 +379,24 @@ namespace Nektar ...@@ -352,19 +379,24 @@ namespace Nektar
typedef std::map<tKey, ModuleEntry, tPredicator> TMapFactory; typedef std::map<tKey, ModuleEntry, tPredicator> TMapFactory;
typedef typename TMapFactory::iterator TMapFactoryIterator; typedef typename TMapFactory::iterator TMapFactoryIterator;
NekFactory() {} NekFactory() : m_mutex() {}
tBaseSharedPtr CreateInstance(tKey idKey BOOST_PP_COMMA_IF(n) tBaseSharedPtr CreateInstance(tKey idKey BOOST_PP_COMMA_IF(n)
BOOST_PP_ENUM_BINARY_PARAMS(n, tParam, x)) BOOST_PP_ENUM_BINARY_PARAMS(n, tParam, x))
{ {
ReadLock vReadLock(m_mutex);
TMapFactoryIterator it = getMapFactory()->find(idKey); TMapFactoryIterator it = getMapFactory()->find(idKey);
if (it != getMapFactory()->end()) if (it != getMapFactory()->end())
{ {
if (it->second.m_func) ModuleEntry *tmp = &(it->second);
vReadLock.unlock();
if (tmp->m_func)
{ {
try try
{ {
return it->second.m_func(BOOST_PP_ENUM_PARAMS(n, x)); return tmp->m_func(BOOST_PP_ENUM_PARAMS(n, x));
} }
catch (const std::string& s) catch (const std::string& s)
{ {
...@@ -385,6 +417,8 @@ namespace Nektar ...@@ -385,6 +417,8 @@ namespace Nektar
tKey RegisterCreatorFunction(tKey idKey, tKey RegisterCreatorFunction(tKey idKey,
CreatorFunction classCreator, CreatorFunction classCreator,
tDescription pDesc = "") { tDescription pDesc = "") {
WriteLock vWriteLock(m_mutex);
ModuleEntry e(classCreator, pDesc); ModuleEntry e(classCreator, pDesc);
getMapFactory()->insert(std::pair<tKey,ModuleEntry>(idKey, e)); getMapFactory()->insert(std::pair<tKey,ModuleEntry>(idKey, e));
return idKey; return idKey;
...@@ -392,6 +426,8 @@ namespace Nektar ...@@ -392,6 +426,8 @@ namespace Nektar
bool ModuleExists(tKey idKey) bool ModuleExists(tKey idKey)
{ {
ReadLock vReadLock(m_mutex);
// Now try and find the key in the map. // Now try and find the key in the map.
TMapFactoryIterator it = getMapFactory()->find(idKey); TMapFactoryIterator it = getMapFactory()->find(idKey);
...@@ -404,6 +440,8 @@ namespace Nektar ...@@ -404,6 +440,8 @@ namespace Nektar
void PrintAvailableClasses(std::ostream& pOut = std::cout) void PrintAvailableClasses(std::ostream& pOut = std::cout)
{ {
ReadLock vReadLock(m_mutex);
pOut << std::endl << "Available classes: " << std::endl; pOut << std::endl << "Available classes: " << std::endl;
TMapFactoryIterator it; TMapFactoryIterator it;
for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it) for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
...@@ -423,6 +461,8 @@ namespace Nektar ...@@ -423,6 +461,8 @@ namespace Nektar
tKey GetKey(tDescription pDesc) tKey GetKey(tDescription pDesc)
{ {
ReadLock vReadLock(m_mutex);
TMapFactoryIterator it; TMapFactoryIterator it;
for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it) for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
{ {
...@@ -439,6 +479,8 @@ namespace Nektar ...@@ -439,6 +479,8 @@ namespace Nektar
std::string GetClassDescription(tKey idKey) std::string GetClassDescription(tKey idKey)
{ {
ReadLock vReadLock(m_mutex);
// Now try and find the key in the map. // Now try and find the key in the map.
TMapFactoryIterator it = getMapFactory()->find(idKey); TMapFactoryIterator it = getMapFactory()->find(idKey);
...@@ -458,6 +500,8 @@ namespace Nektar ...@@ -458,6 +500,8 @@ namespace Nektar
NekFactory& operator=(const NekFactory& rhs); NekFactory& operator=(const NekFactory& rhs);
TMapFactory mMapFactory; TMapFactory mMapFactory;
boost::shared_mutex m_mutex;
}; };
#undef n #undef n
#undef FACTORY_print #undef FACTORY_print
......
...@@ -41,6 +41,8 @@ ...@@ -41,6 +41,8 @@
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/call_traits.hpp> #include <boost/call_traits.hpp>
#include <boost/concept_check.hpp> #include <boost/concept_check.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <LibUtilities/BasicUtils/ErrorUtil.hpp> #include <LibUtilities/BasicUtils/ErrorUtil.hpp>
...@@ -51,6 +53,9 @@ namespace Nektar ...@@ -51,6 +53,9 @@ namespace Nektar
{ {
namespace LibUtilities namespace LibUtilities
{ {
typedef boost::unique_lock<boost::shared_mutex> WriteLock;
typedef boost::shared_lock<boost::shared_mutex> ReadLock;
template <typename KeyType> template <typename KeyType>
struct defOpLessCreator struct defOpLessCreator
{ {
...@@ -76,9 +81,10 @@ namespace Nektar ...@@ -76,9 +81,10 @@ namespace Nektar
typedef std::map<std::string, BoolSharedPtr> FlagContainerPool; typedef std::map<std::string, BoolSharedPtr> FlagContainerPool;
NekManager(std::string whichPool="") : NekManager(std::string whichPool="") :
m_values(), m_values(),
m_globalCreateFunc(), m_globalCreateFunc(),
m_keySpecificCreateFuncs() m_keySpecificCreateFuncs()
{ {
if (!whichPool.empty()) if (!whichPool.empty())
{ {
...@@ -114,6 +120,7 @@ namespace Nektar ...@@ -114,6 +120,7 @@ namespace Nektar
{ {
if (!whichPool.empty()) if (!whichPool.empty())
{ {
ReadLock v_rlock(m_mutex); // reading static members
typename ValueContainerPool::iterator iter = m_ValueContainerPool.find(whichPool); typename ValueContainerPool::iterator iter = m_ValueContainerPool.find(whichPool);
if (iter != m_ValueContainerPool.end()) if (iter != m_ValueContainerPool.end())
{ {
...@@ -122,6 +129,12 @@ namespace Nektar ...@@ -122,6 +129,12 @@ namespace Nektar
} }
else else
{ {
v_rlock.unlock();
// now writing static members. Apparently upgrade_lock has less desirable properties
// than just dropping read lock, grabbing write lock.
// write will block until all reads are done, but reads cannot be acquired if write
// lock is blocking. In this context writes are supposed to be rare.
WriteLock v_wlock(m_mutex);
m_values = ValueContainerShPtr(new ValueContainer); m_values = ValueContainerShPtr(new ValueContainer);
m_ValueContainerPool[whichPool] = m_values; m_ValueContainerPool[whichPool] = m_values;
if (m_managementEnabledContainerPool.find(whichPool) == m_managementEnabledContainerPool.end()) if (m_managementEnabledContainerPool.find(whichPool) == m_managementEnabledContainerPool.end())
...@@ -138,14 +151,14 @@ namespace Nektar ...@@ -138,14 +151,14 @@ namespace Nektar
m_managementEnabled = BoolSharedPtr(new bool(true)); m_managementEnabled = BoolSharedPtr(new bool(true));
} }
} }
~NekManager() ~NekManager()
{ {
} }
/// Register the given function and associate it with the key. /// Register the given function and associate it with the key.
/// The return value is just to facilitate calling statically. /// The return value is just to facilitate calling statically.
bool RegisterCreator(typename boost::call_traits<KeyType>::const_reference key, bool RegisterCreator(typename boost::call_traits<KeyType>::const_reference key,
const CreateFuncType& createFunc) const CreateFuncType& createFunc)
{ {
m_keySpecificCreateFuncs[key] = createFunc; m_keySpecificCreateFuncs[key] = createFunc;
...@@ -170,7 +183,7 @@ namespace Nektar ...@@ -170,7 +183,7 @@ namespace Nektar
{ {
value = true; value = true;
} }
return value; return value;
} }
...@@ -227,6 +240,8 @@ namespace Nektar ...@@ -227,6 +240,8 @@ namespace Nektar
typename ValueContainerPool::iterator x; typename ValueContainerPool::iterator x;
if (!whichPool.empty()) if (!whichPool.empty())
{ {
WriteLock v_wlock(m_mutex);
x = m_ValueContainerPool.find(whichPool); x = m_ValueContainerPool.find(whichPool);
ASSERTL1(x != m_ValueContainerPool.end(), ASSERTL1(x != m_ValueContainerPool.end(),
"Could not find pool " + whichPool); "Could not find pool " + whichPool);
...@@ -234,6 +249,8 @@ namespace Nektar ...@@ -234,6 +249,8 @@ namespace Nektar
} }
else else
{ {
WriteLock v_wlock(m_mutex);
for (x = m_ValueContainerPool.begin(); x != m_ValueContainerPool.end(); ++x) for (x = m_ValueContainerPool.begin(); x != m_ValueContainerPool.end(); ++x)
{ {
x->second->clear(); x->second->clear();
...@@ -246,6 +263,8 @@ namespace Nektar ...@@ -246,6 +263,8 @@ namespace Nektar
typename FlagContainerPool::iterator x; typename FlagContainerPool::iterator x;
if (!whichPool.empty()) if (!whichPool.empty())
{ {
WriteLock v_wlock(m_mutex);
x = m_managementEnabledContainerPool.find(whichPool); x = m_managementEnabledContainerPool.find(whichPool);
if (x != m_managementEnabledContainerPool.end()) if (x != m_managementEnabledContainerPool.end())
{ {
...@@ -263,6 +282,8 @@ namespace Nektar ...@@ -263,6 +282,8 @@ namespace Nektar
typename FlagContainerPool::iterator x; typename FlagContainerPool::iterator x;
if (!whichPool.empty()) if (!whichPool.empty())
{ {
WriteLock v_wlock(m_mutex);
x = m_managementEnabledContainerPool.find(whichPool); x = m_managementEnabledContainerPool.find(whichPool);
if (x != m_managementEnabledContainerPool.end()) if (x != m_managementEnabledContainerPool.end())
{ {
...@@ -276,8 +297,8 @@ namespace Nektar ...@@ -276,8 +297,8 @@ namespace Nektar
} }
private: private:
NekManager(const NekManager<KeyType, ValueType, opLessCreator>& rhs);
NekManager<KeyType, ValueType, opLessCreator>& operator=(const NekManager<KeyType, ValueType, opLessCreator>& rhs); NekManager<KeyType, ValueType, opLessCreator>& operator=(const NekManager<KeyType, ValueType, opLessCreator>& rhs);
NekManager(const NekManager<KeyType, ValueType, opLessCreator>& rhs);
ValueContainerShPtr m_values; ValueContainerShPtr m_values;
BoolSharedPtr m_managementEnabled; BoolSharedPtr m_managementEnabled;
...@@ -285,9 +306,12 @@ namespace Nektar ...@@ -285,9 +306,12 @@ namespace Nektar
static FlagContainerPool m_managementEnabledContainerPool; static FlagContainerPool m_managementEnabledContainerPool;
CreateFuncType m_globalCreateFunc; CreateFuncType m_globalCreateFunc;
CreateFuncContainer m_keySpecificCreateFuncs; CreateFuncContainer m_keySpecificCreateFuncs;
static boost::shared_mutex m_mutex;
}; };
template <typename KeyType, typename ValueT, typename opLessCreator> typename NekManager<KeyType, ValueT, opLessCreator>::ValueContainerPool NekManager<KeyType, ValueT, opLessCreator>::m_ValueContainerPool; template <typename KeyType, typename ValueT, typename opLessCreator> typename NekManager<KeyType, ValueT, opLessCreator>::ValueContainerPool NekManager<KeyType, ValueT, opLessCreator>::m_ValueContainerPool;
template <typename KeyType, typename ValueT, typename opLessCreator> typename NekManager<KeyType, ValueT, opLessCreator>::FlagContainerPool NekManager<KeyType, ValueT, opLessCreator>::m_managementEnabledContainerPool; template <typename KeyType, typename ValueT, typename opLessCreator> typename NekManager<KeyType, ValueT, opLessCreator>::FlagContainerPool NekManager<KeyType, ValueT, opLessCreator>::m_managementEnabledContainerPool;
template <typename KeyType, typename ValueT, typename opLessCreator>
typename boost::shared_mutex NekManager<KeyType, ValueT, opLessCreator>::m_mutex;
} }
} }
......
///////////////////////////////////////////////////////////////////////////////
//
// File Thread.cpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description: Thread manager
//
///////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include "LibUtilities/BasicUtils/Thread.h"
namespace Nektar
{
namespace Thread
{
/**
*
*/
ThreadManagerFactory& GetThreadManagerFactory()
{
typedef Loki::SingletonHolder<ThreadManagerFactory,
Loki::CreateUsingNew,
Loki::NoDestroy,
Loki::SingleThreaded> Type;
return Type::Instance();
}
/**
* @brief ThreadJob implementation
*/
ThreadJob::ThreadJob()
{
// empty
}
/**
*
*/
ThreadJob::~ThreadJob()
{
// empty
}
/**
* Part of the thread interface. Do not use unless you're
* an implementation of ThreadManager.
* @warning Do not use: needs to be public so thread implementation can call it.
*/
void ThreadJob::SetWorkerNum(unsigned int num)
{
m_workerNum = num;
}
/**
*
*/
unsigned int ThreadJob::GetWorkerNum()
{