f



C++ threading could be so simple...

I will appreciate some feedback on these thoughts:

Threads with undeterministic communication (semi-random input/output)
are usually (and best) implemented with some kind of message loop.
However, this gives the headache of having to maintain a switch that,
based on a message ID, cast's the generic base class to a concrete
message. It also means that you have to define the messages and give
them members to convey the needed information.
This is usually quite trivial: To keep the switch as small as
possibly, you would probably use the message ID to cast the message,
extract the members and call a function that handles that specific
message (passing it the members of the message).
This means that you could might as well send the receiving thread a
functor. The receiving thread should simply expose an interface (e.g.
a few functions - possibly members of an abstract class). The calling
thread could then send a functor (in a generic message with a 'virtual
void dispatch()' function) that have the address of the function (and
its arguments) to be executed in the context of the receiving thread:

int foo(int); // Event to trigger in thread B

class MessageBase { public: virtual void dispatch() = 0; };

template</* ... */>
class Message : public MessageBase { /* ... */ };

template</* ... */>
MessageBase* make_message(/* ... */);

void thread_a() {
   // ...
   thread_b_queue.push_back(make_message(&foo, 42));
   // ...
}

void thread_b() {
   while (true) {
     MessageBase* msg = thread_b_queue.get(); // Blocking call
     msg->dispatch();  // Thread 'b' executes the call to 'foo(42)'
     delete msg;
   }
}

Using futures/promises, it will even be possible for thread_a() to get
the value returned from the call to 'foo()'. The promise shall simply
be passed to the Message object.

You can find a working example (sorry but there is not a Makefile)
here: http://cvs.savannah.gnu.org/viewvc/gptm/examples/example01/?root=gptm

The 'library' is stored as a project on Savannah: https://savannah.nongnu.org/projects/gptm/

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
1/10/2010 11:15:53 AM
comp.lang.c++.moderated 10738 articles. 1 followers. allnor (8506) is leader. Post Follow

12 Replies
554 Views

Similar Articles

[PageSpeed] 1

On Jan 10, 4:15 am, Kian Karas <kian.karas....@gmail.com> wrote:
> I will appreciate some feedback on these thoughts:
>
> Threads with undeterministic communication (semi-random input/output)
> are usually (and best) implemented with some kind of message loop.
> However, this gives the headache of having to maintain a switch that,
> based on a message ID, cast's the generic base class to a concrete
> message.

It isn't necessarily so bad.  For example, see http://dlib.net/pipe_ex_2.cpp.html.
In it, a thread reads different types of messages out of a pipe and
deals with each without needing to know about any message ID numbers
or switches.  Although, it must be pointed out, the underlying library
does essentially have switches and ID numbers.  But you can hide all
of that from the user.

>
> You can find a working example (sorry but there is not a Makefile)
> here:http://cvs.savannah.gnu.org/viewvc/gptm/examples/example01/?root=gptm
>
> The 'library' is stored as a project on Savannah:https://savannah.nongnu.org/projects/gptm/

>From what I can see you have a nice way of executing a function in
another thread but I think it would be even better if the user didn't
have to perform pointer casts and deal with raw pointers.  Why not use
some smart pointers or some other kind of object to encapsulate some
of these things?

Cheers,
Davis


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Davis
1/10/2010 8:40:57 PM
Kian Karas schrieb:
> I will appreciate some feedback on these thoughts:
> 
> Threads with undeterministic communication (semi-random input/output)
> are usually (and best) implemented with some kind of message loop.

I think not! A thread can have a message handler which is not a loop.
Some OS have a "handler" which will be called on every incoming message.
  "Dispatching" the message via a switch statement is error prone and
expensive. It is much simpler to call a message function which calls the
correct handler function direct. This could simply be done by using
virtual functions inside the message. This keeps information in the
class itself and is base of object oriented programming.

> However, this gives the headache of having to maintain a switch that,
> based on a message ID, cast's the generic base class to a concrete
> message. It also means that you have to define the messages and give
> them members to convey the needed information.

Why the system should not send well formed message objects? Why I should
destroy all information to a enum or int and have a union data field
when it is much simpler to send the object or a pointer to the object?

> This is usually quite trivial: To keep the switch as small as
> possibly, you would probably use the message ID to cast the message,
> extract the members and call a function that handles that specific
> message (passing it the members of the message).

>From my point of view a cast shows always a design problem if the data
that should casted is local to the application. If there is some data
coming from the "outside world" via IO-streams, a factory for objects
should be the solution. But please not with a switch. The "standard"
factory implementation uses registered object generator functions stored
in some container types. Maybe the construction is done by Clone/Copy
functions or other trivial solutions, maybe based on a static construct
function.


> This means that you could might as well send the receiving thread a
> functor. The receiving thread should simply expose an interface (e.g.
> a few functions - possibly members of an abstract class). The calling
> thread could then send a functor (in a generic message with a 'virtual
> void dispatch()' function) that have the address of the function (and
> its arguments) to be executed in the context of the receiving thread:
> 

Maybe a message could "be" a execution message which is called by the
receiving thread, yes. But this is only one type of message and not as
universal as it sounds :-)

Can you give me an idea why I should make an int from an object, send
the int and some data in a "message" and reconstruct an object in an
receiving thread? A lot overhead I think. Other libs/os use pointers to
messages which allow to send a message to multiple threads/tasks to keep
overhead small.


> int foo(int); // Event to trigger in thread B
> 
> class MessageBase { public: virtual void dispatch() = 0; };
> 
> template</* ... */>
> class Message : public MessageBase { /* ... */ };
> 
> template</* ... */>
> MessageBase* make_message(/* ... */);
> 
> void thread_a() {
>    // ...
>    thread_b_queue.push_back(make_message(&foo, 42));
>    // ...
> }
> 
> void thread_b() {
>    while (true) {
>      MessageBase* msg = thread_b_queue.get(); // Blocking call
>      msg->dispatch();  // Thread 'b' executes the call to 'foo(42)'
>      delete msg;
>    }
> }
> 
> Using futures/promises, it will even be possible for thread_a() to get
> the value returned from the call to 'foo()'. The promise shall simply
> be passed to the Message object.
> 
If a message object is an execution message it could call also a
callback function to transmit the return value of the message execution.
  Each type of message can "decide" that in a total exclusive way with a
trivial common interface. Simply using the operator()() on every
execution message.

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Klaus
1/10/2010 8:40:58 PM
Kian Karas wrote:

> Threads with undeterministic communication (semi-random input/output)
> are usually (and best) implemented with some kind of message loop.
> However, this gives the headache of having to maintain a switch that,
> based on a message ID, cast's the generic base class to a concrete
> message.

The switch-base approach is wrong: you must know all your
msg_ids in advance and must update the implementation when
the set grows, which is error-prone. It doesn't work if the new
msg type comes from, say, a plugin.

For that reason I have implemented a message type-based
dispatcher, which dispatches the call to the best matching
handler, which can be a function, a method ora a delegate.
The term "best matching" means that the dynamic type of the
first actual parameter is closest to the handler's static parameter
type in terms of inheritance depth. For instance:

    class B { virtual ~B(); };
    class C : public B {};

    int handle_B(const B&, float) { return 0; }
    int handle_C(const C&, float) { return 1; }

    dynamic_dispatch<int (const B&, float)> dd(&handle_B); // one must
    // always provide a default handler

    dd.attach(&handle_C); // register a handler for C, the call may be 
located in a plugin

    C c;
    const B& b = c;
    auto r = dd(b, 0.0); // handle_C will be called

However, it uses GCC's cxxabi.h to traverse the list of base classes
of a given class (via casting std::type_info to something else), so, 
strictly
speaking, it is not a C++0x program. But, since the only compiler I'm
interested in is GCC, this is a non-issue. I also use this "design pattern"
in many other places, e.g. exception remapping.

> This is usually quite trivial: To keep the switch as small as
> possibly, you would probably use the message ID to cast the message,
> extract the members and call a function that handles that specific
> message (passing it the members of the message).

A message is not the correct place to store its handling details 
information.

    Best regards
    Piotr Wyderski


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Piotr
1/11/2010 9:32:44 PM
> From what I can see you have a nice way of executing a function in
> another thread but I think it would be even better if the user didn't
> have to perform pointer casts and deal with raw pointers.  Why not use
> some smart pointers or some other kind of object to encapsulate some
> of these things?

If you look at the library (my links in first comment), the user need
*not* do any casts. He need not handle any pointer either (except
those he might wish to pass to the destination thread as argument to
the function in the destination thread - e.g. foo() ).


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Kian
1/12/2010 12:01:35 AM
Hi Kian,
I agree with you.
I use to use queue of messages pretty similar of this pattern you have
written here.
One difference is that I decided to hide the message concept then I
have something like this:

//to post messages..
MessageQueue<ClassX> queue;
queue.Post(&X::Func, 10.0);

//to dispatch messages
queue.Delivery(x); // x.Func(10.0) is called

I also did some optimizations inside the queue like to recycle the
memory of dispatched messages.


On Jan 10, 7:15 am, Kian Karas <kian.karas....@gmail.com> wrote:
> I will appreciate some feedback on these thoughts:
>
> Threads with undeterministic communication (semi-random input/output)
> are usually (and best) implemented with some kind of message loop.
> However, this gives the headache of having to maintain a switch that,
> based on a message ID, cast's the generic base class to a concrete
> message. It also means that you have to define the messages and give
> them members to convey the needed information.
> This is usually quite trivial: To keep the switch as small as
> possibly, you would probably use the message ID to cast the message,
> extract the members and call a function that handles that specific
> message (passing it the members of the message).
> This means that you could might as well send the receiving thread a
> functor. The receiving thread should simply expose an interface (e.g.
> a few functions - possibly members of an abstract class). The calling
> thread could then send a functor (in a generic message with a 'virtual
> void dispatch()' function) that have the address of the function (and
> its arguments) to be executed in the context of the receiving thread:
>
> int foo(int); // Event to trigger in thread B
>
> class MessageBase { public: virtual void dispatch() = 0; };
>
> template</* ... */>
> class Message : public MessageBase { /* ... */ };
>
> template</* ... */>
> MessageBase* make_message(/* ... */);
>
> void thread_a() {
>    // ...
>    thread_b_queue.push_back(make_message(&foo, 42));
>    // ...
>
> }
>
> void thread_b() {
>    while (true) {
>      MessageBase* msg = thread_b_queue.get(); // Blocking call
>      msg->dispatch();  // Thread 'b' executes the call to 'foo(42)'
>      delete msg;
>    }
>
> }
>
> Using futures/promises, it will even be possible for thread_a() to get
> the value returned from the call to 'foo()'. The promise shall simply
> be passed to the Message object.
>
> You can find a working example (sorry but there is not a Makefile)
> here:http://cvs.savannah.gnu.org/viewvc/gptm/examples/example01/?root=gptm
>
> The 'library' is stored as a project on Savannah:https://savannah.nongnu.org/projects/gptm/
>
> --
>       [ Seehttp://www.gotw.ca/resources/clcm.htmfor info about ]
>       [ comp.lang.c++.moderated.    First time posters: Do this! ]



-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Thiago
1/12/2010 12:07:51 AM
Sorry if I have been unclear. My point is *exactly* that having a
message loop (in the OS, thread library or the user code) to dispatch
the messages based on an ID and a cast operation has a lot of
disadvantages.

> Maybe a message could "be" a execution message which is called by the
> receiving thread, yes. But this is only one type of message and not as
> universal as it sounds :-)

It is universal! Please see the example I referenced in my first
comment. If you have a library with functor & bind support (e.g. c++0x
C++ standard library), you can have *any* type of function called at
the destination thread without having to define any message types in
the client code.
Binding the arguments to the function yields an object for which you
can call "operator()()".

If your destination thread defines a different type of base message
(e.g. struct MyMsg { int id }; ), you simply define *one* new message
type that encapsulates the MessageBase (called MessageIf in the
library I have given links to) and allocates an ID for that (needs
only be done once): struct MyMsgX { int id; MessageBase* msg };

> Can you give me an idea why I should make an int from an object, send
> the int and some data in a "message" and reconstruct an object in an
> receiving thread? A lot overhead I think. Other libs/os use pointers to
> messages which allow to send a message to multiple threads/tasks to keep
> overhead small.

It might not have been clear from my example, but sending a pointer to
a message is exactly what I intend (that's what make_message()
returns).

> If a message object is an execution message it could call also a
> callback function to transmit the return value of the message execution.
>   Each type of message can "decide" that in a total exclusive way with a
> trivial common interface. Simply using the operator()() on every
> execution

Yes, adding that feature could be useful.


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Kian
1/12/2010 12:09:26 AM
On Jan 11, 5:01 pm, Kian Karas <kian.karas....@gmail.com> wrote:
> > From what I can see you have a nice way of executing a function in
> > another thread but I think it would be even better if the user didn't
> > have to perform pointer casts and deal with raw pointers.  Why not use
> > some smart pointers or some other kind of object to encapsulate some
> > of these things?
>
> If you look at the library (my links in first comment), the user need
> *not* do any casts. He need not handle any pointer either (except
> those he might wish to pass to the destination thread as argument to
> the function in the destination thread - e.g. foo() ).
>

I see that your library doesn't force the user to use pointers.  But
what I mean to say is, it would be nice if, in addition to the tool in
the example program you linked to, you also had something for creating
the initial thread and calling ThreadScopeIf::run().


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Davis
1/12/2010 2:15:31 AM
On Jan 11, 5:09 pm, Kian Karas <kian.karas....@gmail.com> wrote:
> Sorry if I have been unclear. My point is *exactly* that having a
> message loop (in the OS, thread library or the user code) to dispatch
> the messages based on an ID and a cast operation has a lot of
> disadvantages.
>
> > Maybe a message could "be" a execution message which is called by the
> > receiving thread, yes. But this is only one type of message and not as
> > universal as it sounds :-)
>
> It is universal! Please see the example I referenced in my first
> comment. If you have a library with functor & bind support (e.g. c++0x
> C++ standard library), you can have *any* type of function called at
> the destination thread without having to define any message types in
> the client code.
> Binding the arguments to the function yields an object for which you
> can call "operator()()".
>

I think Klaus has a legitimate point.  For example, what if the
receiving thread has private state that should be modified when
certain messages are received?  Since this state is not in the scope
of the sending thread you will be unable to create a functor that
knows how to modify it.  This seems to be a limitation but maybe I'm
just not thinking about it in the right way.

-Davis


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Davis
1/12/2010 2:15:48 AM
> I see that your library doesn't force the user to use pointers.  But
> what I mean to say is, it would be nice if, in addition to the tool in
> the example program you linked to, you also had something for creating
> the initial thread and calling ThreadScopeIf::run().

Yes, that part of the library dealing with thread creation is
missing.

The library should be updated to use c++0x (threads, futures,
functors, binders etc.).


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Kian
1/12/2010 8:08:34 PM
> > Sorry if I have been unclear. My point is *exactly* that having a
> > message loop (in the OS, thread library or the user code) to dispatch
> > the messages based on an ID and a cast operation has a lot of
> > disadvantages.
>
> > > Maybe a message could "be" a execution message which is called by the
> > > receiving thread, yes. But this is only one type of message and not as
> > > universal as it sounds :-)
>
> > It is universal! Please see the example I referenced in my first
> > comment. If you have a library with functor & bind support (e.g. c++0x
> > C++ standard library), you can have *any* type of function called at
> > the destination thread without having to define any message types in
> > the client code.
> > Binding the arguments to the function yields an object for which you
> > can call "operator()()".
>
> I think Klaus has a legitimate point.  For example, what if the
> receiving thread has private state that should be modified when
> certain messages are received?  Since this state is not in the scope
> of the sending thread you will be unable to create a functor that
> knows how to modify it.  This seems to be a limitation but maybe I'm
> just not thinking about it in the right way.

The intended use of the library is:
1) The 'serving' thread (destination) offers an interface in the form
of a (possibly member) function.
2) Using the library, the 'client' thread (source), will post a
message composing a pointer to the function (including possibly object
and arguments).
3) The destination thread dispatches the message (which will call the
functor - but this is library code).

// server.h
class Server {
public:
   void start(int);
   int stop();
};

// client.cpp
Server& server = /* ... */
// Start server synchronously (call_sync() returns when start()
returns)
call_sync(server_ctx, make_functor(server, &Server::start, 123));

/* Do some stuff ... */

// Stop server asynchronously (call_async() returns as soon as message
is posted on queue */
future<int> result;
call_async(server_ctx, make_functor(server, &Server::stop), result);

/* Do some stuff while waiting for stop() to return */

// Wait for result (if not already present)
int val = result.get();


The private state is implemented in the Server class and modified by
Server::start() and Server::stop(). You simply define and implement
the 'serving' thread as if it was not threaded! It is not the message/
functor that is sent to the serving thread that knows and modifies the
state, it is the functions defined in the serving thread.
You need only expose the functions that other threads can call - just
like sequential programming. Also the definition of the functions need
not use any synchronization objects for this to work - the library
takes care of this before dispatching the message.


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Kian
1/12/2010 8:08:38 PM
Kian Karas wrote:
> I will appreciate some feedback on these thoughts:
> 
> Threads with undeterministic communication (semi-random input/output)
> are usually (and best) implemented with some kind of message loop.
> 
..........
> void thread_a() {
>    // ...
>    thread_b_queue.push_back(make_message(&foo, 42));
>    // ...
> }
> 
> void thread_b() {
>    while (true) {
>      MessageBase* msg = thread_b_queue.get(); // Blocking call
>      msg->dispatch();  // Thread 'b' executes the call to 'foo(42)'
>      delete msg;
>    }
> }
> 
......

This is pretty inefficient.
I think this would be better:
virtual void produce() {
     // ... some blocking mechanism, like io,
      // process data then
     _queue.push_back(make_message(&foo,42));
     // ...
}
void consume() {
      while(auto_ptr<MessageBase> msg = _queue.get()) // blocks only if
locked by other thread
       msg->dispatch();  // executes the call to 'foo(42)'
  }

in base Thread class:

int Thread::run()
{
	while(!shutdown())
         {
             produce(); // waits for data
             consume(); // performs work
         }
   return 0;
}
In this way you can avoid condition variable in _queue.get() which
adds large overhead because threads have to sleep twice, producer on
io stream, consumer on condition variable...
With this approach you can get 40k requests per second instead just
4k , for example on cygwin, windows...

Greets

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Branimir
1/13/2010 3:02:37 AM
On Jan 12, 1:26 pm, Kian Karas <kian.karas....@gmail.com> wrote:
> > > Sorry if I have been unclear. My point is *exactly* that having a
> > > message loop (in the OS, thread library or the user code) to dispatch
> > > the messages based on an ID and a cast operation has a lot of
> > > disadvantages.
>
> > > > Maybe a message could "be" a execution message which is called by the
> > > > receiving thread, yes. But this is only one type of message and not as
> > > > universal as it sounds :-)
>
> > > It is universal! Please see the example I referenced in my first
> > > comment. If you have a library with functor & bind support (e.g. c++0x
> > > C++ standard library), you can have *any* type of function called at
> > > the destination thread without having to define any message types in
> > > the client code.
> > > Binding the arguments to the function yields an object for which you
> > > can call "operator()()".
>
> > I think Klaus has a legitimate point. For example, what if the
> > receiving thread has private state that should be modified when
> > certain messages are received? Since this state is not in the scope
> > of the sending thread you will be unable to create a functor that
> > knows how to modify it. This seems to be a limitation but maybe I'm
> > just not thinking about it in the right way.
>
> The intended use of the library is:
> 1) The 'serving' thread (destination) offers an interface in the form
> of a (possibly member) function.
> 2) Using the library, the 'client' thread (source), will post a
> message composing a pointer to the function (including possibly object
> and arguments).
> 3) The destination thread dispatches the message (which will call the
> functor - but this is library code).
>
> // server.h
> class Server {
> public:
> void start(int);
> int stop();
>
> };
>

[snip]

>
> The private state is implemented in the Server class and modified by
> Server::start() and Server::stop(). You simply define and implement
> the 'serving' thread as if it was not threaded!

This is my point.  Suppose the start() and stop() functions should
never be called by the main thread.  Maybe they aren't thread safe (as
you say, implement them as if they are not threaded).  Or maybe there
is some architectural reason why you don't want other threads
executing those functions.  In this case it is nice to be able to make
those functions private.  However, in your example the calling thread
could make direct calls to start() and stop().  Encapsulation is just
as important for member functions as it is for member variables.

Although, to counter my own complaint.  It is easy enough to add a
factory method to Server that does nothing but construct a functor
with the necessary pointer to start() or stop() in it and return a
copy.  Or it might create the functor and dispatch it to the thread
itself.

So I relent.  This is quite general purpose :)

It would probably be a good idea to have an example program that shows
the case where the server_ctx is a private member and the other thread
only does things like call public member functions that dispatch the
appropriate asynchronous calls to private member functions.  This
would preempt the next guy who would otherwise complain about this :)

Cheers,
Davis


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Davis
1/14/2010 4:19:58 AM
Reply: