[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