Parallel method calls to server
Havoc Pennington
hp at redhat.com
Sat Nov 25 15:17:32 PST 2006
Hi,
Pallavi Rao wrote:
> In a serialized/synchronous method call, two different
> clients, client1 and client2 call the same method A on
> a serving object and they are worked upon one after
> the other. So that after the first method call from
> client1 is done with, the second call from client2 is
> taken care of(and replies are received in the same
> order at the clients).
Clarifying one point, the ordering is not guaranteed between two
messages sent by two different clients - ordering is only guaranteed
with respect to each client.
For each message queue (DBusConnection), that queue is ordered. However,
if there are two queues, there are no ordering guarantees between them.
So if you send two messages from the same DBusConnection, the server
will receive and process those messages in the same order you sent them.
But if you send one message from connection A and another message from
connection B, the server may receive and process those messages in any
order.
Obviously you can impose stronger ordering guarantees by doing your own
synchronization. In other words, if you send a message on connection A,
wait for a reply from the server confirming it was processed, and only
then send a message on connection B, then you know the first message was
processed first.
But if you send both messages at the same time, on two different
connections, without synchronizing by waiting for the reply on the first
one, there's no ordering.
This is a little confusing since there are three processes involved in a
typical method call, let's say the method caller, the bus daemon, and
the method handler.
In the typical case, the method caller and the method handler each have
one DBusConnection to the bus daemon. The bus daemon has a bunch of
DBusConnection, and it moves messages from each connection to other
interested connections.
If the method caller sends three method calls, those are all going
through the same connection; the bus daemon will thus read and process
them in the same order they were sent. The bus daemon will then write
them to other connections, including the message handler's connection,
in the order of processing. The message handler will receive the three
method calls, in order, on its one connection. The message handler then
sends back three replies, which stay *in order the handler sent them* as
the daemon processes them, and are received back by the message caller
still *in order the handler sent them*.
So nothing gets reordered by libdbus or the bus daemon, as long as it's
on a single connection. However note that the method handler *can*
process each method call out-of-order. For example, if the method
handler is multithreaded and uses a different thread for handling each
message, you would expect replies to be out-of-order.
Also, again if there's a second method caller B, and it also sends three
calls; there is NO ordering with respect to the messages from the first
method caller A. The method handler could process three methods from A,
then three from B; or it could do B first then A; or it could interleave
those methods.
In short:
- each DBusConnection is a queue, and things in a queue stay in order.
- after a method handler removes messages from a queue, it has the
option to process them out-of-order (for some messages this makes sense
and for others it would be a disaster - it's a domain-specific question)
- when the bus daemon forwards a message from an incoming queue to an
outgoing queue, it preserves the order of the incoming messages.
- the bus daemon reads from all its incoming queues and writes to its
outgoing in arbitrary order, so there is no ordering between two
messages unless they are coming from and going into the same queue
> In a parallel/asynchronous call, a thread(?) is
> generated per each single call to this method A. So
> for two calls from two clients to a single method at
> the same time, two separate threads run in parallel to
> finish work at the same or almost the same time.
This is not exactly the case; libdbus never creates threads, and
dbus-daemon is not multithreaded. However, dbus-daemon *is* completely
asynchronous (it never blocks), which means that it behaves exactly as
if it had a thread per connection. So you can think of it as
multithreaded if you like and you will draw the right conclusions.
You would draw the *wrong* conclusions if you think of the bus daemon as
having a thread per *message*. The bus daemon processes only one
message at a time, in order to preserve the ordering guarantees for
messages from the same queue. The bus guarantees that if it reads
message A1 then A2 from the same connection, it will write those
messages to outgoing connections in the order A1 then A2.
If the daemon had a thread per *message* then it might reorder stuff in
all kinds of ways, unless it had a big global lock (in which case the
threads would have no purpose). So multithreading the bus daemon is
almost certainly pointless because the protocol guarantees a fair bit of
synchronization.
In your own application, you need not provide the same ordering
guarantees as the bus daemon. Once you read messages from the ordered
incoming queue (DBusConnection), you can process them out-of-order if
you like, using either threads or nonblocking IO.
There's no global answer to whether this makes sense. For example if you
have two method calls like:
Init();
DoStuff();
then you probably don't want to process those in two threads, since the
Init() needs to happen first and then the DoStuff().
But if you have two unrelated method calls, the order in which you
process them might not make any difference and parallelization could be
a speed win.
The method caller can always force two methods to run in sequence by
waiting for a reply to the first before sending the second.
> In
> this case a reply from a thread is to be sent back to
> the right client to which it belongs.
> Does the dbus directly deal with the threads in this
> case, or should that all be done inside the server
> object? (I guess dbus has generally not anything to do
> with this, but I am not sure.)
libdbus won't ever create threads, that's up to the application.
> In other words, I am searching for information/
> documentation on how the multithreaded applications
> are dealt on the dbus??
There is a lock on each DBusConnection, so it is safe to send messages
(method replies or method calls) from multiple threads. For example, two
different threads might each dbus_connection_send_with_reply_and_block()
at the same time. Or if you are handling two messages in parallel in two
threads, each thread can safely send back its reply to the same
DBusConnection object.
However, it is the application's problem to figure out when parallel
processing and reduced ordering guarantees are in fact acceptable. For a
method caller, usually you can just call methods willy-nilly from any
thread you want, since presumably each method caller thread is unrelated
to the others.
For method handlers, if you have any ordering issues between your
methods (such as an Init() call that must be handled first), it's
probably a bad idea to run them in parallel, unless you provide for some
kind of locking that preserves the important ordering.
But as long as your method handler is stateless (like an HTTP server),
handling multiple calls in parallel should not be a problem.
You should almost certainly avoid calling dbus_connection_dispatch() (or
other functions that cause a dispatch, see the docs) from more than one
thread; because the dispatch will happen in whichever thread you call
dispatch() from, and this is unlikely to be sane.
> Is it also possible to have new and proper processes
> with unique PID's instead of threads, per each call in
> the parallel implementation of serving applications.
> (Then the processes, for example, can have unique
> connection names !)
It sounds possible (in effect the bus daemon is doing something like
that), but you'd have to design and implement such a system yourself.
libdbus is just giving you the stream of incoming messages in order;
your application is responsible for any parallelization, using threads
or processes or any other mechanism you like.
Havoc
More information about the dbus
mailing list