Re: [Quantlib-dev] Quantlib within a multithreaded architecture.
Posted by Luigi Ballabio on
URL: http://quantlib.414.s1.nabble.com/ANN-QuantLib-0-3-7-released-tp3088p3090.html
On 08/02/2005 06:02:44 AM, Toyin Akin wrote:
> I've been working with QuantLib the last serveral months looking at
> the possibility of producing a commercial multithreaded .NET engine.
> The main problem I have found which would prevent this from working
> within a multi-threaded environment (Wrapper on top of the C++
> layer), are those of the 3 Singleton classes.
>
> ExchangeRateManager, IndexManager and Settings.
Toyin,
apologies for the delay. I still have some catch-up to do after
my vacations...
As to the multithreading issue: man, is this a tricky one.
It seems to me that adding an explicit parameter---be it the evaluation
date, a thread or session ID, or some other kind of settings
object---would percolate through and pollute too many interfaces. It
should be added as a parameter to Instrument::NPV(),
Instrument::calculate(), YieldTermStructure::whatever(),
Xibor::fixing(), CashFlow::amount()... it is painful just to think of
it. I would very like prefer that Settings remained globally accessible.
But on the other hand, we should be able to have different threads get
hold of different Settings instances, otherwise they will either have
to be serialized (defeating the very purpose of threads) or step on
each other's toes. A few months ago, Ashish Kulkarni mentioned
thread-local storage; as far as I can see, it seems an interesting
possibility---although I'm not sure that we can code it in the library
directly and in a portable way. Moreover, the library might be called
from different languages, and they might provide their own thread
implementation.
At this time, I'm inclined to turn the Singleton class into a Multiton
and add a hook so that different instances can be requested behind the
curtains. I'm thinking of an implementation along the lines of:
#if defined(QL_ALLOW_SESSIONS)
Integer sessionId(); // note: declared, but not defined in
// the library itself
#endif
T& Singleton<T>::instance() const {
static std::map<Integer, boost::shared_ptr<T> > instances_;
#if defined(QL_ALLOW_SESSIONS)
Integer id = sessionId();
#else
Integer id = 0;
#endif
boost::shared_ptr<T>& instance = instances_[id];
if (!instance)
instances_[id] = instance = boost::shared_ptr<T>(new T);
return *instance;
}
When QL_ALLOW_SESSIONS is undefined (which would be the default) the
singleton will work as it does now. However, users wanting to have
different instances will have the possibility to #define it. In this
case, they'll have to define their own implementation of sessionId(),
which will return a different id for different threads, and link it
with the library. This will give them the possibility to implement
sessionId() in the most convenient way, e.g., using thread-local
storage in a C++ application, calling back to Python or Ruby to
interrogate their thread manager if the library is exported to such
languages, or doing whatever is necessary in .NET to get a thread id.
Thoughts?
Later,
Luigi
----------------------------------------
Quote me as saying I was misquoted.
-- Groucho Marx