bug-gettext
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Multithreading advice on the manual


From: Bruno Haible
Subject: Re: Multithreading advice on the manual
Date: Fri, 09 Jun 2023 22:44:11 +0200

Miguel Ángel Arruga Vivas wrote:
> >> The multithreaded example contains a race condition
> >> (volatile doesn't mean atomic)
> >
> > This is not a problem.
> 
> A data race like this does not mean that the function might be called
> more than once, it means that the behaviour of the whole program from
> that point on is undefined.  I'm reading the C11 draft (N1570) section
> 5.1.2.4, point 4 and annex J, section 2 Undefined Behaviour, point 1,
> 5th bullet.

Of course the standard has to, in the general case, say that a data race
can cause undefined behaviour. But that does not mean that a program
will crash just because two threads read and write from the same (4-bytes-
long and word-aligned!) memory location.

> In this case, an hypothetical compiler, library and processor
> combination may well place the read and the write together (they are
> volatile lvalues, not memory fences), and sleep on that thread before
> performing the call to bindtextdomain.

No, it can't. According to the code [1]
  - First the libfoo_initialized variable gets read,
  - Then the bindtextdomain() function gets executed. This includes
    acquiring a lock and releasing a lock.
  - Then the libfoo_initialized variable gets set to true.

Paul Eggert says [3][4] that since libfoo_initialized is static and the
compiler can therefore prove that the bindtextdomain() call will not modify
it, the compiler is usually allowed to move either the read or the write of
a variable across an acquire+release of a lock. But this does not hold
for 'volatile' static variables (cf. ISO C 11 § 6.7.3.(7)).

> After gathering this information, what do you think of changing volatile
> to _Atomic?

It still has portability problems: Compilers typically implemented
the _Atomic keyword together with the <stdatomic.h> header, and the
<stdatomic.h> header is missing on several platforms [2].

> It won't produce ill-formed programs now, not by 2030.
> bindtextdomain might be called more than once, but it's ensured that it
> will be called before the first library call to dcgettext.

That's also ensured with 'volatile'.

Without the 'volatile',
  - the compiler could cache the value of libfoo_initialized, thus - in the
    worst case - calling libfoo_initialize() each time,
  - the compiler could move the 'libfoo_initialized = true;' statement
    around and thus - in the scenario you described - possibly invoke
    foo_refcount before bindtextdomain.

I'll apply the patch below, to clarify.

Bruno

[1] https://www.gnu.org/software/gettext/manual/html_node/Libraries.html
[2] https://lists.gnu.org/archive/html/bug-gnulib/2023-06/msg00073.html
[3] 
https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.71/html_node/Volatile-Objects.html
[4] https://lists.gnu.org/archive/html/bug-gnulib/2006-07/msg00210.html


diff --git a/gettext-tools/doc/gettext.texi b/gettext-tools/doc/gettext.texi
index 75f87291c..05ce76bd1 100644
--- a/gettext-tools/doc/gettext.texi
+++ b/gettext-tools/doc/gettext.texi
@@ -3060,8 +3060,10 @@
 @end example
 
 @noindent
-The more general solution for initialization functions, POSIX
-@code{pthread_once}, is not needed in this case.
+The more general solutions for initialization functions, POSIX
+@code{pthread_once} or ISO C @code{call_once}, are not needed in this
+case, because the @code{bindtextdomain} function is multithread-safe
+(it serializes its invocations through a lock) and idempotent.
 
 @item
 The usual declaration of the @samp{_} macro in each source file was






reply via email to

[Prev in Thread] Current Thread [Next in Thread]