The threading specs in the standard: a new catastrophe

M

Marcin Grzegorczyk

sfuerst said:
[...]
Assuming you use a CS as a mutex, then the only nontrivial thing to
have is PTHREAD_MUTEX_INITIALIZER. Fortunately, recent versions of
Microsoft windows allow static initialization of these via the
definition:
#define PTHREAD_MUTEX_INITIALIZER {(void*)-1,-1,0,0,0,0}

Can you point me to some documentation please?

The CRITICAL_SECTION structure is defined in Winnt.h

Description of what the fields do is described here:
http://msdn.microsoft.com/en-us/magazine/cc164040.aspx

Note, however, that the article is not an official Microsoft
documentation, and indeed there's an Editor's Note at the top, which
says one should not use such tricks in production code.
 
M

Marcin Grzegorczyk

Jens said:
Am 07.07.2011 23:14, schrieb Ian Collins:

I find two important features missing though,
PTHREAD_MUTEX_INITIALIZER and PTHREAD_COND_INITIALIZER. Not having
them will make the initialization of simple critical sections quite
clumbsy.

Or is it tacidly implied in the standard that the default
initialization of static mutexes and conditions will to the right
thing?

No such thing is implied in the draft Standard. The reason is that some
existing mutex implementations do not provide static initialization;
most notably, under Win32, neither mutex objects nor critical section
objects do (barring some tricks that may break if Microsoft decides to
change the underlying implementation, again).
 
S

sfuerst

sfuerst said:
[...]
Assuming you use a CS as a mutex, then the only nontrivial thing to
have is PTHREAD_MUTEX_INITIALIZER.  Fortunately, recent versions of
Microsoft windows allow static initialization of these via the
definition:
#define PTHREAD_MUTEX_INITIALIZER {(void*)-1,-1,0,0,0,0}
Can you point me to some documentation please?
The CRITICAL_SECTION structure is defined in Winnt.h
Description of what the fields do is described here:
http://msdn.microsoft.com/en-us/magazine/cc164040.aspx

Note, however, that the article is not an official Microsoft
documentation, and indeed there's an Editor's Note at the top, which
says one should not use such tricks in production code.

Which doesn't prevent Microsoft from using the technique in its own C
library one little bit. ;-)

Steven
 
J

Jens Gustedt

Am 10.07.2011 00:02, schrieb Marcin Grzegorczyk:
No such thing is implied in the draft Standard. The reason is that some
existing mutex implementations do not provide static initialization;
most notably, under Win32, neither mutex objects nor critical section
objects do (barring some tricks that may break if Microsoft decides to
change the underlying implementation, again).

Hm, I first thought that a once_flag could be used to launch an
initializer function for such statically objects. As such this is not
possible, since the call_once interface doesn't allow the function
parameter to receive an argument.

But an implementation would have to provide call_once & Co. So you'd
have to have
- some sort of atomic read of the once_flag
- the potential to delay all but one threads that stumble into this
simultaneaously
- the potential to have the very first thread call an initialization
function

These ingredients could be used equally well to call an mtx_init and
cnd_init on statically initialized objects, I think. Performance cost
of such things should be minor.

Jens
 
M

Marcin Grzegorczyk

Jens said:
Am 10.07.2011 00:02, schrieb Marcin Grzegorczyk:

Hm, I first thought that a once_flag could be used to launch an
initializer function for such statically objects. As such this is not
possible, since the call_once interface doesn't allow the function
parameter to receive an argument.

But an implementation would have to provide call_once & Co. So you'd
have to have
- some sort of atomic read of the once_flag
- the potential to delay all but one threads that stumble into this
simultaneaously

Yes; indeed, that's how one implements Win32 critical section
initialization when explicit initialization is not feasible for some
reason (and one doesn't want to rely on undocumented tricks).
These ingredients could be used equally well to call an mtx_init and
cnd_init on statically initialized objects, I think. Performance cost
of such things should be minor.

One problem is, what to do if the actual initialization of the mutex
(which may entail allocation of system resources) fails. POSIX simply
states that things should be implemented such that it cannot fail (see
the Rationale section of
<http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html>),
but it's not realistic to put such a requirement on all implementations;
and allowing mtx_*lock() to return thrd_nomem would be a divergence from
the pthreads practice.

Of course, what I just said does not mean WG14 cannot yet reconsider
this point; I just consider it unlikely.
 
J

Jens Gustedt

Am 11.07.2011 21:05, schrieb Marcin Grzegorczyk:
and allowing mtx_*lock() to return thrd_nomem would be a divergence from
the pthreads practice.

why thrd_nomem?

I think in such a case they should just return the error code that
mtx_init would have returned. mtx_init only has thrd_sucess and
thrd_error as return codes. mtx_lock has exactly the same, mtx_trylock
adds thrd_busy to that. So the error returns of these function would
not have to be reconsidered.
Of course, what I just said does not mean WG14 cannot yet reconsider
this point;

I find the argument in the pthread specification about the advatages
of offering static initialization really convincing.
I just consider it unlikely.

You are probably right. At the end this interface will probably not be
used by the people, even if we'd see some implementation, soon.

But this re-enforces the initial point of this thread (put aside the
polemics) that this interface is not yet mature. It would probably
have been better to just add a definition of "simultaneous execution"
of some sort. This then could have been the basis of the atomic
stuff.

The part on atomic types and functions (macros) is really important in
my point of view, because I am not aware of any standardization of
these operations. This is some gray zone where all compilers and
systems have some extensions.

Jens
 
M

Marcin Grzegorczyk

Jens said:
Am 11.07.2011 21:05, schrieb Marcin Grzegorczyk:

why thrd_nomem?

That's the intended return value when some resources cannot be
allocated. But yes, thrd_error would work about as well in practice.
(In practice, I suspect most existing pthreads code does not even bother
to check the return value of pthread_mutex_lock().)

[...]
I find the argument in the pthread specification about the advatages
of offering static initialization really convincing.

It certainly does simplify things quite a bit.

[...]
At the end this interface will probably not be
used by the people, even if we'd see some implementation, soon.

We'll see. The benefits of having a standard interface may well
outweigh its limitations.

As for implementation, AFAIK the interface is based on a subset of the
Dinkumware library.
 
J

Jens Gustedt

Am 11.07.2011 23:56, schrieb Marcin Grzegorczyk:
That's the intended return value when some resources cannot be
allocated.

no, not for mtx_init. in n1570 it only has thrd_error as an error
indication.
But yes, thrd_error would work about as well in practice.
(In practice, I suspect most existing pthreads code does not even bother
to check the return value of pthread_mutex_lock().)

yes. In practice, on hosted environments running out of memory during
initialization is probably nothing that is heard of much.
As for implementation, AFAIK the interface is based on a subset of the
Dinkumware library.

I don't think that just one proprietary implementation will contribute
to a wide spread acceptance. You'd need at least one major compiler
implementor adopt it on each side, windows and unix. On the unix side
this'd better be gcc or clang, so something with an open license of
some sort.

Jens
 
M

Marcin Grzegorczyk

Jens said:
Am 11.07.2011 23:56, schrieb Marcin Grzegorczyk:

no, not for mtx_init. in n1570 it only has thrd_error as an error
indication.

I meant the general description of the enumeration constants in 7.26.1.

[...]
I don't think that just one proprietary implementation will contribute
to a wide spread acceptance. You'd need at least one major compiler
implementor adopt it on each side, windows and unix. On the unix side
this'd better be gcc or clang, so something with an open license of
some sort.

Glibc, rather than GCC. If the final standard includes the <threads.h>
as the current draft describes it, I expect it to be implemented pretty
soon in glibc (after all, it's just a thin wrapper over pthreads).
 
J

Jens Gustedt

Am 07/16/2011 01:14 AM, schrieb Marcin Grzegorczyk:
Glibc, rather than GCC. If the final standard includes the <threads.h>
as the current draft describes it, I expect it to be implemented pretty
soon in glibc (after all, it's just a thin wrapper over pthreads).

So you distiguish the threads support from the atomic support? The
real advantage would be to have them both, I think, and they are
closely related.

For atomic most can probably be done in the library respectively in
header files with inline functions (are they allowed to be macros?)
that just map to the gcc builtins. But a direct support of _Atomic
would at least need some integration in the compiler itself.

Jens
 
J

Jens Gustedt

Hello,

Am 07/18/2011 09:50 PM, schrieb Alexander Terekhov:

This is already a start, but not the same as implementing the _Atomic
keyword in C1x, I guess. This goes more in direction of implementing
the atomic macro/functions by the help of builtins.

You'd have to synthesize the correct arithmetic operations for all
primitive types for which the compiler is supposed to support _Atomic.

Jens
 
A

Alexander Terekhov

Jens said:
Hello,

Am 07/18/2011 09:50 PM, schrieb Alexander Terekhov:

This is already a start, but not the same as implementing the _Atomic
keyword in C1x, I guess. This goes more in direction of implementing
the atomic macro/functions by the help of builtins.

You'd have to synthesize the correct arithmetic operations for all
primitive types for which the compiler is supposed to support _Atomic.

I think that _Atomic keyword sucks miserably. I also don't like
C++0x atomics.

I think that atomic loads and stores ought to support the following
'modes':

Whether load/store is competing (default) or not. Competing load
means that there might be concurrent store (to the same object).
Competing store means that there might be concurrent load or
store. Non-competing load/store can be performed non-atomically.

Whether competing load/store needs remote write atomicity (default
is no remote write atomicity). A remote-write-atomicity-yes load
triggers undefined behaivior in the case of concurrent remote-
write-atomicity-no store.

Whether load/store has specified reordering constraint (default
is no constraint specified) in terms of the following reordering
modes:

Whether preceding loads (in program order) can be reordered
across it (can by default).

Whether preceding stores (in program order) can be reordered
across it (can by default).

Whether subsequent loads (in program order) can be reordered
across it (can by default). For load, the set of constrained
subsequent loads can be limited to only dependant loads (aka
'consume' mode).

Whether subsequent stores (in program order) can be reordered
across it (can by default). For load, there is an implicit
reordering constraint regarding dependent stores (no need to
specify it).

A fence/barrier operation can be used to specify reordering
constraint using basically the same modes.

regards,
alexander.
 
M

Marcin Grzegorczyk

Jens said:
Am 07/16/2011 01:14 AM, schrieb Marcin Grzegorczyk:

So you distiguish the threads support from the atomic support?

The WG14 certainly has agreed they are different things; that's why
there is __STDC_NO_ATOMICS__ in the first place (earlier drafts had just
__STDC_NO_THREADS__).

For the rationale, see the WG14 documents N1553 (comment CA 4) and N1558
(pp.14-15). In summary, atomics can be useful even without threads
(e.g. on embedded systems).
 
A

Alexander Terekhov

Marcin said:
The WG14 certainly has agreed they are different things; that's why
there is __STDC_NO_ATOMICS__ in the first place (earlier drafts had just
__STDC_NO_THREADS__).

For the rationale, see the WG14 documents N1553 (comment CA 4) and N1558

N1555:

"There is a current macro that says if
you have stdc_no_threads, if that is
defined, then you don’t need to provide
the stdcatomic.h header. These are
different things. Specifically, threads
belong to the OS and atomics belongs
to the hardware. In embedded system,
you want hardware support and not
have OS come along for the ride. "
(pp.14-15). In summary, atomics can be useful even without threads

"Threads and atomics are different
things. Specifically, threads belong
to the OS and atomics belong to the
hardware. The OS should provide common
locking implementations so that
different compilers don't do
incompatible things. In embedded
system, you want hardware support and
not have OS come along for the ride.
We should separate __STDC_NO_THREADS
from stdatomic.h. We suggest
__STDCATOMIC__ be defined if the
system provides atomics and the
atomic header.

We would have atomics in all cases,
with or without threads."

<chuckles>

The quoted N1555 et al text above is
utter nonsense.

Without threads, we already have
sig_atomic_t.

regards,
alexander.
 
J

Jens Gustedt

Am 07/22/2011 09:36 PM, schrieb Alexander Terekhov:
Without threads, we already have sig_atomic_t.

I don't think that this is a satisfactory interface. Giving guarantees
for load/store operations beyond signal handlers would probably be a
win.

But I agree that having atomic as widely defined as it is is difficult
to understand without a model for threads.

Jens
 
A

Alexander Terekhov

FYI:

http://www.cl.cam.ac.uk/~pes20/cppppc/top.pdf
("Clarifying and compiling C/C++ concurrency: from C++0x to POWER")

"Abstract

The upcoming C and C++ revised standards add concurrency to
the languages, for the first time, in the form of a subtle relaxed
memory model (the C++0x model). This aims to permit compiler
optimisation and to accommodate the differing relaxed-memory
behaviours of mainstream multiprocessors, combining simple semantics
for most code with high-performance low-level atomics for
concurrency libraries. We make two contributions:
We first establish two simpler but provably equivalent models
for C++0x, one for the full language and another for the subset
without consume operations. Subsetting further to the fragment
without low-level atomics, we identify a subtlety arising from
atomic initialisation.
We then prove our main result, the correctness of a proposed
compilation scheme of the C++0x concurrency primitives
to POWER assembly, having noted that an earlier proposal was
flawed. (The main ideas apply also to ARM, which has a similar
relaxed memory architecture.)
This should inform the ongoing development of production
compilers for C++0x and C1x, clarifies what properties of the
machine architecture are required, and builds confidence in the
C++0x and POWER semantics."

regards,
alexander.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top