thread-safety of counters

Simon McVittie simon.mcvittie at collabora.co.uk
Mon Feb 23 04:56:30 PST 2015


On 23/02/15 11:23, Adrian Szyndela wrote:
> Let's consider a simple test program that:
> 1. creates a D-Bus connection;
> 2. creates a few threads that share the connection;
> 3. then, threads perform method calls over the connection.

This is meant to work, but I don't recommend it. I would recommend GIO's 
GDBus module, particularly for multi-threaded D-Bus: its design is 
explicitly multi-threaded.

Please be careful to distinguish between D-Bus, the protocol, and 
libdbus, the reference implementation of that protocol (as shipped 
alongside dbus-daemon in dbus.git). I consider GDBus to be a better 
D-Bus implementation for most purposes than libdbus.

> If answer is no, then I have another question: is there any place that
> describes what is thread-safe in dbus and what is not?

libdbus is theoretically thread-safe, but its level of thread-safety is 
mostly developer folklore rather than something that is explicitly 
documented. I believe sharing a "large" object like a DBusConnection 
(perhaps also a DBusServer?) between multiple threads is *meant* to 
work, whereas any API call other than ref/unref on a DBusMessage 
requires the calling thread to "own" that message, and I'm not sure 
about objects of intermediate size like DBusPendingCall.

One DBusConnection per thread is more likely to work than one 
DBusConnection shared between many threads; if you do share one 
DBusConnection between many threads, then restricting yourself to 
"dispatching" in at most one "owner" thread, and only performing 
blocking method calls in the other threads (as QtDBus does), is more 
likely to work than anything more complicated.

Unfortunately, libdbus was designed to be suitable for all uses with few 
assumptions (e.g. any or no main-loop abstraction, any or no 
multi-threading design), with the predictable result that instead of 
doing one thing well and everything else not at all, it does lots of 
things but none of them very well. D-Bus reimplementations like GDBus, 
and libdbus wrappers like QtDBus, can do a lot better by fixing some of 
the details: for instance, GDBus requires the GLib main loop (which it 
runs in a worker thread so that calling code is not necessarily required 
to use it too, although that is also encouraged), and QtDBus requires 
the Qt main loop.

> There are two messages involved, but both point to the same counter
> (connection->transport->live_messages).

I thought this counter was meant to be protected by one of the 
connection's mutexes (it has three - dispatch_mutex, io_path_mutex and 
mutex - because libdbus tries to be all things to all people and support 
an assortment of unlikely threading models). But I could be wrong...

> As a conclusion, I suggest changing DBusCounter's refcount from int to
> DBusAtomic, as in DBusMessage.

This seems reasonable, but it would be good to know whether the counter 
is meant to be protected by a mutex. If so, why was that mutex not 
sufficient here? and if not, how do we avoid getting an incorrect value 
in the counter via concurrent access from different threads?

-- 
Simon McVittie
Collabora Ltd. <http://www.collabora.com/>



More information about the dbus mailing list