Re: C++ threading could be so simple...
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! ]