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