- Thread-safe initialization of static objects - 17 Updates
- Problem with calling C++ from Fortran - 8 Updates
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:
Post a Comment