6

I am implementing a message passing algorithm. Messages pass between adjacent nodes when they have enough information at the node to compose the message - information that is passed to the node from neighbouring nodes. The implementation is trivial if I make each of messages a thread and use boost::condition to put the thread to sleep until the required information is available.

Unfortunately - I have 100k nodes in the graph which would mean 300k threads. When I asked how to make that many threads the answer was that I shouldn't - and re-design instead.

My question is: is there a standard design pattern for waiting for a condition? Perhaps some asynchronous control pattern?

EDIT: I think I can do this with the proacator pattern. I have edited to tags to include boost::asio - to see if anyone has suggestions with this.

So the discussion can be concrete, here is how the messages are defined so far:

class
Message
{
public:      
  Message(const Node* from, Node* to)
    : m_from(from), m_to(to)
  {}
  void
  operator()()
  {
    m_to->ReceiveMessage( m_from->ComposeMessage() );
  }
private:
  Node *m_from, *m_to;
};

These message functors are currently launched with boost::thread. Then we have

class Node
{
    Node(Node* Neighbour1, Node* Neighbour2, Node* Neighbour3); 
   // The messages (currently threads) are created on construction, 
   // The condition locks then sort out when they actually get passed 
   // without me having to think too hard.

    void ReceiveMessage(const Message&); 
    //set m_message from received messages;
    //EDIT This looks like an async write - use boost asio here?

    Message 
    ComposeMessage()
    {
      // If possible I want to implement this function without threads
      // It works great but it if every message is a thread 
      // then I have 300k threads.
      // EDIT: this looks like an async read (use boost asio here?)

      boost::mutex::scoped_lock lock(m_mutex);
       while (!m_message) //lock the thread until parameter is set.
        m_cond.wait(lock);
      return *m_message;
   }
  private:
    boost::optional<Message> m_message;
    boost::mutex m_mutex;
    boost::condition m_cond;
}

I like the transparency of the code and if possible would like to keep the same interfaces by having some alternative to the conditional lock?

Community
  • 1
  • 1
Tom
  • 5,219
  • 2
  • 29
  • 45
  • Sounds like you're more or less reinventing CSP. How about finding a CSP library that does all this for you? – jalf Apr 22 '11 at 10:00
  • @Jaif - I think you are right. I hadn't heard of CSP (I knew not doing Computer Science would get me in the end). It seems I have some googling to do... – Tom Apr 22 '11 at 10:08

1 Answers1

3

I guess what you are looking for is the reactor pattern. This is where most of the activities do not take too much time and they are doing co-operative multitasking. See node.js for a JavaScript implementation of the idea, but in C++ the ACE library provides this concept out-of-the-box allowing multiple threads based on the number of cores in the system.

These libraries all depend on some OS APIs that support non-blocking IO on disks, network, etc. When you are not waiting for the OS, but another message source in your app, they provide you with the tools for that.

wigy
  • 2,174
  • 19
  • 32
  • thank you, a very interesting article and the Ace library looks like it might do the trick. – Tom Apr 22 '11 at 10:26