Saturday, September 9, 2023

Digest for comp.lang.c++@googlegroups.com - 25 updates in 2 topics

Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo>: Sep 08 08:14PM -0400

Chris M. Thomasson wrote:
 
>>> Yup. It uses address based hashing into the fixed mutex table.
 
>> I guess that's not used at all in the runtimes.
 
> Why not?
 
I think it's not needed in general for static initialization purpose.
 
This is because, if our design choice for our "C++ compiler" is to use a
dedicated mutex (or once_flag control) per a static variable that
requires dynamic initialization, nothing prevents our compiler from
allocating a static instance of such mutex or control next to the static
variable.
 
Because mutex and once_flag can be constant-initialized (at least in
POSIX, notably Linux), the code that dynamically initializes a variable
can directly use the address of its respective constant-initialized
mutex or control, as in the following example:
 
code in C++ source file:
 
static type1 var1 = InitVar1();
 
**pseudo-code** actually generated by the compiler:
 
pthread_once_t __var1_once_control = PTHREAD_ONCE_INIT; /* generated
by the compiler when */
 
static type1 var1 = InitVar1(); /* this is compiled to,
**in pseudo-code**, to something like
 
pthread_once( [&var1]() { var1 = InitVar1(); } );
*/
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Sep 08 06:05PM -0700

On 9/8/2023 5:14 PM, Pavel wrote:
> **in pseudo-code**, to something like
 
>  pthread_once( [&var1]() { var1 = InitVar1(); } );
> */
 
pthread_once is perfectly fine. Just wondering, are you creating the
POSIX impl directly here?
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Sep 08 06:10PM -0700

On 9/8/2023 6:05 PM, Chris M. Thomasson wrote:
>> */
 
> pthread_once is perfectly fine. Just wondering, are you creating the
> POSIX impl directly here?
 
Think of how you would directly implement pthread_once... There are many
different ways.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Sep 08 06:22PM -0700

On 9/7/2023 2:55 AM, Paavo Helde wrote:
> critical section for thread-safe statics initialization.
> EnterCriticalSection() does not return any error code and of course does
> not throw any C++ exceptions either, so it is supposed to never fail.
 
If it does fail, then some rather radical shit has hit the fan.
 
 
 
> So I gather that in case the thread-safe static init synchronization
> fails, there must be a bug in the implementation. No C++ exceptions
> would be thrown anyway.
 
Right. The implementation must get it right using fine grain locking,
amortized table locking, or some other means. The compiler and POSIX
worth together like a system. Iirc, I saw another way that was
lock-free, but allowed a thread to create an object, then might have to
delete it because it was not the first one to be installed in the sense
of being visible to other threads. This was decades ago, iirc it used
CAS. No mutex.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Sep 08 06:45PM -0700

On 9/8/2023 6:22 PM, Chris M. Thomasson wrote:
> delete it because it was not the first one to be installed in the sense
> of being visible to other threads. This was decades ago, iirc it used
> CAS. No mutex.
 
Iirc it was something like:
 
static foo* g_foo = nullptr;
 
foo* l_foo = g_foo; // atomic load
 
if (! l_foo)
{
foo* t_foo = new foo;
foo* cmp = nullptr;
 
// CAS would update the comparand on failure.
// Take special note of that...
 
// mb release
 
if (! CAS(&g_foo, &cmp, t_foo)) // atomic rmw
{
// failed!!! well, shit happens!
delete t_foo;
t_foo = cmp;
// mb acquire
}
}
 
else
{
// mb acquire
}
 
l_foo->bar();
Bonita Montero <Bonita.Montero@gmail.com>: Sep 09 05:26AM +0200

Am 08.09.2023 um 22:26 schrieb Chris M. Thomasson:
 
> Why not?
 
Because there are simpler ideas that work.
Bonita Montero <Bonita.Montero@gmail.com>: Sep 09 05:44AM +0200

Am 08.09.2023 um 20:54 schrieb Pavel:
 
> As per the above yield-based waiting for initialization is not slower
> than mutex-based. Hence, this "unacceptably slow is nonsense.
 
Of course it is slower because you wait N timeslices.
 
> A thread that waits for the contended mutex is, upon locking the mutex,
> scheduled identically to yield so no difference with mutex
 
No, a thread waiting for a mutex doesn's spin when the thread holding
the spinlock is scheduled away but it is sleeping inside the kernel.
That's more efficient.
 
> On the opposite, I can see in glibc source code that pthread_once for
> linux (which is most common) does not use mutex. There is no "creation",
> pthread_once_t is an int.
 
pthread_once uses a mutex internally for sure.
Paavo Helde <eesnimi@osa.pri.ee>: Sep 09 05:54PM +0300

09.09.2023 06:44 Bonita Montero kirjutas:
 
> pthread_once uses a mutex internally for sure.
 
pthread_once source code can be found by google:
https://elixir.bootlin.com/glibc/latest/source/nptl/pthread_once.c
 
From there I can see that it calls atomic_load_acquire(). Only if this
fails, will it call __pthread_once_slow() in the slow branch, which uses
futexes. Some other googling reveals that: "a futex ("Fast Userspace
Mutex") isn't a mutex at all"
Bonita Montero <Bonita.Montero@gmail.com>: Sep 09 07:26PM +0200

Am 09.09.2023 um 16:54 schrieb Paavo Helde:
 
> fails, will it call __pthread_once_slow() in the slow branch, which uses
> futexes. Some other googling reveals that: "a futex ("Fast Userspace
> Mutex") isn't a mutex at all"
 
Doesn't matter since the standard should honor static initialization
that fails because of synchronization woes. And as I've shown with
my code MSVC, libstdc++ and libc++ have a mutex per static initiali-
zation, so pthread_once doesn't apply here.
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo>: Sep 09 01:42PM -0400

Bonita Montero wrote:
> that fails because of synchronization woes. And as I've shown with
> my code MSVC, libstdc++ and libc++ have a mutex per static initiali-
> zation, so pthread_once doesn't apply here.
 
If Microsoft implemented standard wrongly, it's Microsoft's failure, not
the standard's.
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo>: Sep 09 01:44PM -0400

Chris M. Thomasson wrote:
>> */
 
> pthread_once is perfectly fine. Just wondering, are you creating the
> POSIX impl directly here?
I am not creating, just demonstrating in pseudo-code how Linux
implementation could work.
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo>: Sep 09 02:00PM -0400

Chris M. Thomasson wrote:
>> POSIX impl directly here?
 
> Think of how you would directly implement pthread_once... There are many
> different ways.
You are correct, there are. Fortunately, I don't have to reinvent this
particular wheel as the implementation source code is available for
everyone to read. On Linux, Futex is a natural choice.
 
Other platforms can have theirs. I did not program for Windows for long
time but I would at least try to implement call_once with a critical
section (whose creation, contrary to OP's insinuations, cannot fail
since Windows Vista).
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Sep 09 11:41AM -0700

On 9/9/2023 11:00 AM, Pavel wrote:
> time but I would at least try to implement call_once with a critical
> section (whose creation, contrary to OP's insinuations, cannot fail
> since Windows Vista).
 
Iirc, Windows has a futex like "thing". I cannot remember the API right
now. Will get back to you.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Sep 09 11:45AM -0700

On 9/8/2023 8:26 PM, Bonita Montero wrote:
> Am 08.09.2023 um 22:26 schrieb Chris M. Thomasson:
 
>> Why not?
 
> Because there are simpler ideas that work.
 
Not exactly sure how to parse that, but sure. As long as it works.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Sep 09 11:48AM -0700

On 9/8/2023 8:44 PM, Bonita Montero wrote:
 
> No, a thread waiting for a mutex doesn's spin when the thread holding
> the spinlock is scheduled away but it is sleeping inside the kernel.
> That's more efficient.
 
So, you must really dislike adaptive mutex designs, right? If so, why?
They can spin several times before waiting in the kernel... Really slow
path, so to speak. Btw, do you think that adaptive mutex are really bad?
If so, why?
 
 
 
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Sep 09 11:49AM -0700

On 9/9/2023 10:26 AM, Bonita Montero wrote:
> that fails because of synchronization woes. And as I've shown with
> my code MSVC, libstdc++ and libc++ have a mutex per static initiali-
> zation, so pthread_once doesn't apply here.
 
Huh? pthread_once totally applies here. Windows has futex like abilities.
Bonita Montero <Bonita.Montero@gmail.com>: Sep 09 09:15PM +0200

Am 09.09.2023 um 19:42 schrieb Pavel:
 
> If Microsoft implemented standard wrongly, it's Microsoft's failure, not
> the standard's.
 
The standard doesn't say anything to the issue I've shown.
db <dieterhansbritz@gmail.com>: Sep 09 10:54AM +0200

I want to call a C++ function from Fortran. The function is
called jband, in the file jband.cpp. The function is of type
long double, and so is its argument tbar.
I wrote this:
 
module STUFF
integer, parameter :: dbl=selected_real_kind(14)
integer, parameter :: qud=selected_real_kind(30)
end module STUFF
program JBAND_TEST
use STUFF; implicit none
real(dbl) :: curr, FORTJBAND
real(qud) :: tbar
do
read *, tbar
if (tbar < 0) exit
curr = FORTJBAND (tbar)
print '(" curr =", f10.4)', curr
enddo
end program JBAND_TEST
 
function FORTJBAND (tbar)
use STUFF; implicit none
interface
function JBAND (tbar) bind(c)
import JBAND, c_long_double
import tbar, c_long_double
end function JBAND
end interface
real(dbl) :: FORTJBAND
real(qud) :: tbar
FORTJBAND = JBAND (tbar)
end function FORTJBAND
 
I run this using this script
 
g++ -o jband.o jband.cpp
gfortran -o jbandtest.o jbandtest.f90
gfortran jband.o jbandtest.o
./a.out << eoi
1.0
-1
eoi
rm a.out jband.o jbandtest.o
 
and I get this output
 
/usr/bin/ld:
/usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/Scrt1.o: in
function `_start':
(.text+0x1b): undefined reference to `main'
collect2: error: ld returned 1 exit status
jbandtest.f90:21:31:
 
21 | import JBAND, c_long_double
| 1
Error: Cannot IMPORT 'c_long_double' from host scoping unit at (1) -
does not exist.
jbandtest.f90:22:30:
 
22 | import tbar, c_long_double
| 1
Error: Cannot IMPORT 'c_long_double' from host scoping unit at (1) -
does not exist.
jbandtest.f90:27:14:
 
27 | FORTJBAND = JBAND (tbar)
| 1
Error: Type mismatch in argument 'tbar' at (1); passed REAL(16) to REAL(4)
[...]
 
So there is a communication problem with agreeing on the C++
type long double.
I have tried making everything in jband plain double, making
the two statements
 
import JBAND, c_double
import tbar, c_double
 
but now it says that C-double doesn't exist.
 
Any ideas?
 
 
 
--
Dieter Britz
Muttley@dastardlyhq.com: Sep 09 09:02AM

On Sat, 9 Sep 2023 10:54:33 +0200
>but now it says that C-double doesn't exist.
 
>Any ideas?
 
C++ mangles function names so that the name you give the function isn't the
name the dynamic loader sees in the binary. You need to put this around whatever
function you want to call from Fortran so it has C style linkage which means
the name remains the same:
 
extern "C" {
 
void calledFromFortran()
{
:
}
 
}
db <dieterhansbritz@gmail.com>: Sep 09 12:47PM +0200

> :
> }
 
> }
 
Like this:
 
const long double iband(const long double tbar)
extern "C" {
 
void calledFromFortran()
{
:
}
 
}
 
? Why the extra } ?
--
Dieter Britz
Muttley@dastardlyhq.com: Sep 09 10:51AM

On Sat, 9 Sep 2023 12:47:38 +0200
>> }
 
>> }
 
>Like this:
 
No. calledFromFortran was an example function.
 
extern "C" {
 
const long double iband(const long double tbar)
{
:
}
 
}
 
>? Why the extra } ?
 
What extra } ? The brackets balance.
db <dieterhansbritz@gmail.com>: Sep 09 12:52PM +0200

On 09.09.2023 12.47, db wrote:
> }
 
> }
 
> ? Why the extra } ?
 
Now I get a new error, due to this "extern"
 
~/ownlib90/tests> ./jbandtest
jband.cpp:88:1: error: expected initializer before 'extern'
88 | extern "C" {
| ^~~~~~
jband.cpp:96:1: error: expected unqualified-id before '{' token
96 | {
| ^
jbandtest.f90:21:31:
 
21 | import JBAND, c_long_double
| 1
Error: Cannot IMPORT 'c_long_double' from host scoping unit at (1) -
does not exist.
[...]
 
--
Dieter Britz
Muttley@dastardlyhq.com: Sep 09 11:00AM

On Sat, 9 Sep 2023 12:52:42 +0200
>Error: Cannot IMPORT 'c_long_double' from host scoping unit at (1) -
>does not exist.
>[...]
 
If your knowledge of C++ syntax is so basic you don't know which bits go
where I'd suggest getting someone else to write the C++ code and you stick
to fortran.
Paavo Helde <eesnimi@osa.pri.ee>: Sep 09 04:56PM +0300

09.09.2023 13:52 db kirjutas:
> jband.cpp:96:1: error: expected unqualified-id before '{' token
>    96 | {
>       | ^
 
Assuming you are indeed compiling this as C++ as intended, the problem
must be with the preceding content.
 
> Error: Cannot IMPORT 'c_long_double' from host scoping unit at (1) -
> does not exist.
> [...]
 
This is a fortran error message. It's not very likely you will get any
help about this here, most people here do not know anything about fortran.
"Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Sep 09 04:30PM +0200

On 2023-09-09 12:47 PM, db wrote:
 
>> }
 
> Like this:
 
> const long double iband(const long double tbar)
 
Why did you add that?
 
You could at least try to do /exactly/ the example given by a
knowledgeable person.
 
 
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: