- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
So far I have gone into a rabbit hole. InterlockedAdd is an intrinsic to MS, not in a lib, so I guess I have to make a dll in MSVC that invokes InterlockedAdd and returns result.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Kernel32.f90 has:
INTERFACE FUNCTION InterlockedExchangeAdd( & Addend, & Value) import integer(LONG) :: InterlockedExchangeAdd ! LONG !DEC$ ATTRIBUTES DEFAULT, DECORATE, ALIAS:'__ifort_InterlockedExchangeAdd' :: InterlockedExchangeAdd integer(LONG), intent(INOUT) :: Addend ! LPLONG Addend !DEC$ ATTRIBUTES REFERENCE, IGNORE_LOC :: Addend integer(LONG), intent(IN) :: Value ! LONG Value !DEC$ ATTRIBUTES VALUE :: Value END FUNCTION END INTERFACE
This returns the old value prior to interlocked add
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
For completeness, here are the set of interlocked operations defined in KERNEL32:
InterlockedIncrement, InterlockedDecrement, InterlockedExchange, InterlockedExchangeAdd, InterlockedCompareExchange
For coarray programs, there are a bunch of ATOMIC_xxx intrinsics, such as ATOMIC_ADD.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Also, you can use OpenMP ATOMIC
!$omp atomic capture oldValue = x x = x + expression ! .OR. !$omp atomic capture x = x + expression newValue = x
The first returns prior value, the second returns resultant value.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@jimdempseyatthecove:
Thanks, I did not know about source like kernel32.f90. I was dumbin'ing kernel32.lib and getting nowhere. Using the code gets
"error #6623: The procedure name of the INTERFACE block conflicts with a name in the encompassing scoping unit. [INTERLOCKEDEXCHANGEADD]".
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This compiles except for the error#6623 above, but I would have thought I should have a CPI1 C_PTR declared and used:
INTEGER :: I0 =1 INTEGER(C_INT), VOLATILE, TARGET :: I1 = 2 INTEGER :: I2= 8 I0 = INTERLOCKEDEXCHANGEADD(I1,I2)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
mwindham wrote:This compiles except for the error#6623 above, but I would have thought I should have a CPI1 C_PTR declared and used:
INTEGER :: I0 =1 INTEGER(C_INT), VOLATILE, TARGET :: I1 = 2 INTEGER :: I2= 8 I0 = INTERLOCKEDEXCHANGEADD(I1,I2)
You can try this, note the IA32 (effectively 32-bit) environment. On x64 (64-bit), use InterLockedExchangeAdd64.
use, intrinsic :: iso_c_binding, only : c_long interface function InterlockedExchangeAdd(Addend,Value) result(r) bind(C, name="InterlockedExchangeAdd") !DIR$ ATTRIBUTES STDCALL :: InterlockedExchangeAdd ! MSDN function prototype: ! https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedexchangeadd ! LONG InterlockedExchangeAdd( ! LONG volatile *Addend, ! LONG Value !); import :: c_long implicit none ! Argument list integer(c_long), volatile, intent(inout) :: Addend integer(c_long), value, intent(in) :: Value ! Function result integer(c_long) :: r end function end interface ! Local variables integer(c_long) :: I0 = 1 integer(c_long), volatile :: I1 = 2 integer(c_long) :: I2 = 8 I0 = InterlockedExchangeAdd(I1, I2) print *, "I0 = ", I0 stop end
Upon compilation, linking, and execution:
C:\Temp>ifort /standard-semantics /warn:all /stand:f18 p.f90 Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on IA-32, Version 19.1.0.085 Pre-Release Beta Build 20190522 Copyright (C) 1985-2019 Intel Corporation. All rights reserved. p.f90(5): warning #7025: This directive is not standard F2018. !DIR$ ATTRIBUTES STDCALL :: InterlockedExchangeAdd ------------^ Microsoft (R) Incremental Linker Version 14.21.27702.2 Copyright (C) Microsoft Corporation. All rights reserved. -out:p.exe -subsystem:console p.obj C:\Temp>p.exe I0 = 2 C:\Temp>
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think the error#6623 above was a clash with something already in kernel32.f90. This works ith LOC(i1) but does not compile with the C_LOC(I1) arg. In debugger i1 is 10. program Interlocked1 USE KERNEL32 use iso_c_binding implicit none ! Variables INTEGER :: I0 =1 INTEGER(C_INT), VOLATILE, TARGET :: I1 = 2 INTEGER :: I2= 8 ! Body of Interlocked I0 = INTERLOCKEDEXCHANGEADD(LOC(I1),I2) !I0 = INTERLOCKEDEXCHANGEADD(C_LOC(I1),I2) print *, 'Hello World' end program Interlocked1
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks to all.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
mwindham wrote:I think the error#6623 above was a clash with something already in kernel32.f90. This works ith LOC(i1) but does not compile with the C_LOC(I1) arg. In debugger i1 is 10. ..
Refer to the documentation for the non-standard LOC function, an Intel Fortran extension, and the standard-supported intrinsic function of C_LOC from ISO_C_BINDING intrinsic module (https://software.intel.com/en-us/fortran-compiler-developer-guide-and-reference-c-loc) whose return type in a Fortran-standard defined derived type of C_PTR and not what the interface for InterLockedExchangeAdd expects,
Separately, the interface declaration is already to setup to do the 'work' in terms of 'pass by reference' of the first parameter in that function, so you don't need to use LOC nor C_LOC with it.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@FortranFan
if LOC(I1) was omitted, I got exception for trying to access address 0x00000002.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
mwindham wrote:@FortranFan
if LOC(I1) was omitted, I got exception for trying to access address 0x00000002.
It's straight forward with using the Windows OS included C++ function in kernel32.dll from Microsoft as shown above in Quote #7.
I'm unsure of the interface with alias '__ifort_InterlockedExchangeAdd' in Intel Fortran provided kernel32.f90 file.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@FortranFan
Your codes works, as does mine(both compiled 32-bit). Mine requires LOC and uses kernel32.f90 interface; yours is explicit.
So does this, without TARGET:
program Interlocked1a USE KERNEL32 use iso_c_binding implicit none ! Variables INTEGER :: I0 =1 INTEGER, VOLATILE :: I1 = 2 INTEGER :: I2= 8 ! Body of Interlocked I0 = INTERLOCKEDEXCHANGEADD(LOC(I1),I2) print *, "I1 = ", I1 end program Interlocked1a
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quote #2 was right and I got it wrong by trying to redo interface in kernel32.f90 in mine first time around. I am confused about what IGNORE_LOC does? It seems a LOC for Addend is needed.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
mwindham wrote:Quote #2 was right and I got it wrong by trying to redo interface in kernel32.f90 in mine first time around. I am confused about what IGNORE_LOC does? It seems a LOC for Addend is needed.
If you are able to contact Intel Support, you may want to inquire with them re: Kernel32.f90 interface for Fortran. One would have thought the 'IGNORE_LOC' attribute is present in the interface so that one doesn't need to use LOC, so something appears amiss.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jim has shown the x64 declaration of that routine. On x64, Windows expects this API to be implemented by a compiler intrinsic and consequently it is not exported from kernel32.dll. ifort's runtime implements the API itself - hence the alias to an ifort runtime helper routine. The declaration and implementation of that helper routine is such that LOC does not have to be used (default calling convention, the Addend argument is passed by reference, IGNORE_LOC will do what it suggests).
The definition for x86 is different - LOC is required. On x86 this API is implemented using an export from kernel32.lib, the declaration is consistent with other API's (stdcall calling convention, the argument is passed by value, consequently the value passed needs to be the address of the thing that you want to exchange and add).
But... why are you calling this API?
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page