Re: Concurrent Data Structures (Was: Concurrent Containers)
"Scott Meyers" <NeverRead@aristeia.com>
Good, the point is that the interface must not have a single function
be used that way, and be unsafe.
Oh, don't be silly. Of course it can. Or would you ban operator from
arrays and vectors, because people can use invalid indices?
No. I don't think those play in the same category. op usage indeed has
the chance to pass a bad index, and I certainly saw many situations to find,
review or even create such a bug. But I'm yet to meet a programmer who is
not aware that the obligation of keeping the passed thing in bounds is
there. Or who is confused about the fact that whatever expression
evaluates between  shall give a proper number.
Race conditions are subtle, programmers who just "see" them are rare and
precious, and too many do not learn to feel such errors even after
accidents, reviews, whatever.
If it makes you feel any better, TBB has the convention of prefixing
concurrency-unsafe operations in their concurrent containers with
"unsafe," e.g., "unsafe_erase" and "unsafe_bucket_count" on
They do? Yeah, that makes me absolutely feel feel better. If you
sometimes write guidelines that touch threading and interfaces, a written
advice to follow similar practice would make my day for sure.
Also, if the component covers my MT work only halfway -- I have to use
synch incantations for at least some operations, then the gain on the
operations is moot.
Since when do you reject a library component because you have to write
some custom code to work with it? Do you write your own containers from
scratch because the STL ones don't have exactly the interface you need for
your applications, or do you write some custom code with the interface you
want and use STL under the hood to implement that interface?
Let's not go to extreme relativization (or what is it called ;-). Writing a
container (or most library stuff) involves many lines of code.
Inserting critical sections where they are needed is just a few lines.
Working with traditional objects in the MT environment is not a big deal, if
your overall design is sound, and you did identify the points of sharing.
Using a magic class that just does to good thing is cool. But replacing the
traditional way with some half-halping thing will hurt more than help,
Also, if the object does locking that is not evidently showing its spots,
easy to create deadlock situations, you only need another mutex, say from
another such hash_map.
From TBB's documentation on concurrent_unordered_map:
The interface has no visible locking. It may hold locks internally,
but never while calling user defined code.
That is at least a clear. :) (I recall a tough situation from practice, we
created an observer framework, that called registered notification functions
on certain events -- and holding a lock on the collection we iterated on was
bad, but releasing it also created a bag of possible problems.)
In C++ it is easy to overlook 'user code' usage, especially with a template
I think your objections boil down to "it's possible for people to do a bad
job with the design and implementation of a concurrent data structure."
They might choose bad names, they might design error-prone APIs, they
might not think about deadlock.
No, this is not my main problem. It's more around the communication gap
that involves this whole topic. Let's just assume that people creating
those libs know MT in and out, and are aware of all the problem cases.
And even document them precisely. What kind of knowledge you expect from
the audience programmers, to have safe results?
Let's look a parallel. Who can write a string class? Sure, anyone. But
Joe Average's string class will likely have some leaks if exceptions happen,
maybe even other problems. While a good programmer can write it to be all
correct and sound.
Then once the latter guy published his class, that Joe can use the class all
year without being able to leak memory. Probably even without careful study
of the manual.
With MT I see that the user shall know as much as the pro just to evaluate
which component to pick from the library, and how to use it. JA will be
lost with basic elements -- and about as lost with more specialised lib.
Yet, as I tried to state earlier, I do not onject writing those libs. They
are by all means welcome. I just did not see too much payoff from them,
or even the possibility. Because my similar-looking use cases turned out
to have differences that flushed chance of good generalization.
You're right, they might. But if the possibility of bad design and
implementation choices were the only consideration, nobody would be
allowed to program anything in C++.
Well, I don't want to offend anyone, but I actually believe that programming
is not a sport for everyone, and programming in UB-infested languages like C
or C++ is even so. Practicing as a doctor, lawyer, architect and many
other disciplines are tied to licence and quality control, that the software
field painfully lacks -- and that cause a big deal of losses in life, limb
and property. but that leads far offtopic ;-)
I think that if you were to look at the TBB/PPL concurrent container APIs
instead of simply imagining what they might be, you'd see that those APIs
were designed with care.
Sure, I will, and thanks to bring them to my attention.
Still my real problem is not with the libraries, but their users. ;)