[Development] Question about QCoreApplicationData::*_libpaths
Marc Mutz
marc.mutz at kdab.com
Fri Jan 22 20:46:54 CET 2016
On Friday 22 January 2016 18:34:26 Matthew Woehlke wrote:
> On 2016-01-22 13:13, Marc Mutz wrote:
> > On Friday 22 January 2016 17:44:40 Thiago Macieira wrote:
> >> On Friday 22 January 2016 11:14:47 Marc Mutz wrote:
> >>> On Friday 22 January 2016 09:57:00 Иван Комиссаров wrote:
> >>>> What
> >>>> i'm missing?
> >>>
> >>> You haven't done the exercise with the int first.
> >>
> >> Here's the exercise with int. This is thread-safe:
> >>
> >> int f()
> >> {
> >>
> >> return 1;
> >>
> >> }
> >>
> >> auto x = f();
> >> ++x;
> >>
> >> No matter how many threads call f(), all of them will get a value from
> >> f, can assign it to a variable and modify without caring what other
> >> threads do.
> >>
> >> Replace int with QMap or QString and you have the same behaviour.
> >
> > This part of the discussion was about copying a container. You return a
> > new instance instead. Returning a new instance does not copy, nor move,
> > due to NRVO.
>
> The same assertions would hold if Thiago had written:
>
> int f()
> {
> static int result = 1;
> return result;
> }
>
> ...or anything else for the body of f().
>
> And in fact, you're again attacking a straw man. The implementation of
> getMap() was not shown; for all you know, it too might have returned a
> new instance every time. (Probably not, but doesn't matter.)
>
> What matters is that the result is returned *by value*. It is thread
> safe because it is not a reference, it is a copy. Qt containers are
> likewise thread safe because they behave (in a thread-safe manner) *as
> if* an actual copy was made (even though the actual copy might not
> happen until some time later, if ever).
QVector and std::vector have exactly the same threading guarantees: concurrent
reads are ok, but if you have writers, all access (incl. reads) need to be
synchronized.
So what you are so upset about can only be that in the case of std::vector,
the copy is made immediately, and with QVector later, or never.
Whether one or the other is faster depends on so many factors that one cannot
give a single correct answer. It depends. On how frequently the copy is
modified. On the payload type. On the size of the vector. How often the
function is accessed.
Just one example:
If you hammer the function returning the QVector, you will see massive
contention on the atomic int. Since the atomic int is embedded into the same
memory chunk as the data, so is the beginning of the data (this could be fixed
by padding the header to a cache line width). That means each iteration in
every thread geta a hw mutex lock on reading the first few items.
If the same function returned a std::vector, given a scalable allocator, the
readers are completely insulated from each other, each core's cache can
contain the whole data without cache-line pingpong.
Which one is faster? On a dual-core, probably QVector. On a 64-core processor,
probably std::vector.
And all of this moot, since thread-safe object are pretty rare. Qt itself
contains maybe 10. The std library maybe a handful. And if you care about
performance there, you probably need some lockfree container, anyway. And once
you have to externally synchronise access to the object, a const-& becomes a
very valid option again.
But, yes, as I wrote in "Understand the Qt containers" one area where CoW may
actually be useful is in MT code. I posted a hacky code snippet there that
updated a container without mutex locking, except for two very brief moments
at the beginning and end, retrying if another thread was faster.
But again, CoW can be retrofitted onto any value type (e.g. shared_ptr<const
T>), while CoW types will never be truly value types.
Thanks,
Marc
--
Marc Mutz <marc.mutz at kdab.com> | Senior Software Engineer
KDAB (Deutschland) GmbH & Co.KG, a KDAB Group Company
Tel: +49-30-521325470
KDAB - The Qt Experts
More information about the Development
mailing list