This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug c++/20099] -pthreads should imply -fno-threadsafe-statics
- From: "davids at webmaster dot com" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 23 Feb 2005 02:19:28 -0000
- Subject: [Bug c++/20099] -pthreads should imply -fno-threadsafe-statics
- References: <20050220004607.20099.davids@webmaster.com>
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
------- Additional Comments From davids at webmaster dot com 2005-02-23 02:19 -------
> It's not the question of optimization but correctness.
Exactly, and not locking objects that may be modified from another thread is
not correct. Only the programmer knows whether an object may be modified from
another thread.
> Having an "initialize on first use" semantics which breaks when
> multiple threads use it is as wrong as using global variables
> for passing data between functions and forcing clients to
> introduce locks to make them reentrant.
It doesn't break when multiple threads use it, it breaks when multiple threads
use it in a way where one thread might modify an object while another thread
access it without locking. POSIX specifies that everything breaks when misused
this way.
You seem to have an attitude that it's difficult to track data dependencies
and ensure correct locking. You talk about "unfortunate timing". What you're
missing is that this is what people who write multithreaded programs do all
day long. Those who are good at writing multithreaded programs are good at
doing exactly this. And this change does not remove any of the burden -- it
simply removes a choice (one can trivially add these locks when one knows
they're needed or doesn't know they're not needed).
> It is usable when
> clients are careful, but it's a bad default when we can't
> expect all calls to be done from a single thread.
Any function that might be called from multiple threads concurrently will
require special coding to deal with this situation. You would have to go out
of your way to create a situation where just protecting the initialization is
sufficient.
You have to be careful when you write multithreaded code, period. Functions
may require you to hold certain locks when you call them, prohibit you from
holding other locks, or require the callers to impose synchronization. This is
not some obscure detail unique to COFU, it's the bread and butter of
multithreaded programming.
POSIX puts the responsibility fully on the application programmer to place
locks where there might be concurrent access. In exchange for this effort, the
programmer gets the performance benefit of there not being locks when they are
not needed.
Some hypothetical multithreaded C++ standard might choose a different route.
But it would not be POSIX.
Again, it is this simple: POSIX prohibits an object from being modified in one
thread and accessed in another. C++ specifies initialization on first use.
Initialization is modification. Thus first use requires a lock if there can be
a concurrent access. The language cannot tell when there can and cannot be a
concurrent access, the language cannot tell when a call cannot possibly be
first use.
I could perhaps ignore all of this if the behavior discussed made a reasonably
significant category of code "just work" or removed some of the work involved
in getting synchronized code correct, but it does not. In the vast majority of
cases, the static object may be modified and locks will be needed anyway. In
many cases, it will be known that the static object has already been
intialized and will not be modified, and the locks added will be wasted.
--
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20099