- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
When I add the window api subroutine "Sleep" to my collection, it did not work as intended. It turned out that there is another subroutine "Sleep". The following program does run fine:
PROGRAM sleep_demo ! USE IFPORT ! hè?? not needed IMPLICIT none ! INTEGER :: time1, time2, rate ! CALL SYSTEM_CLOCK(COUNT=time1, COUNT_RATE=rate) CALL sleep(10) ! suspend for 10 seconds CALL SYSTEM_CLOCK(COUNT=time2) WRITE(*,*) 'elapsed time:', REAL(time2-time1)/REAL(rate) ! STOP END PROGRAM sleep_demo
Surprisingly, there is no need to use IFPORT (or any other related module.) although its addition does not harm. I expect compiling and linking this program according to the standard to produce an unresolved reference to "Sleep". But that is not the case. It works fine. (The winapi routine "Sleep" takes as an argument the number of milliseconds to wait.)
It this correct?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
SLEEP takes INTEGER(4) duration in seconds
SLEEPQQ takes INTEGER(4) duration in milliseconds
Both supplied routines require IFPORT.
Due to "CALL sleep(10)" SLEEP or _SLEEP or other decorated name will be produced depending on platform and options. For it to link with Sleep is unexpected. What is your platform and options (both compiler and linker), as well as any additional objs and libraries you link to the program?
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The ifort provided SLEEP is a Fortran 77 style external procedure. All the IFPORT module does is provide an explicit interface for that procedure, that in this case lets the compiler check that the programmer isn't doing something silly (in other cases it would also enable the procedure to use Fortran 90 style argument declarations, such as deferred shape/allocatable/optional, but SLEEP doesn't have anything fancy like that). You can find the source for the IFPORT module with the interface in your compiler installation directory tree.
By being a Fortran 77 style external procedure, SLEEP can be called from Fortran 77 code - no USE statements, no interface blocks, etc.
The compiler emits directives into the object code that it generates, that instructs the linker that it should link against a set of default libraries that are pretty much required for any Fortran program. libifport, which contain the ifort provided SLEEP procedure, is one of those default libraries, hence the linker is able to find the definition of the external procedure.
Without a use statement for IFPORT (or otherwise providing an interface block for SLEEP), the sleep procedure is being referenced via an identifier that does not have the EXTERNAL attribute - there is nothing in the supplied Fortran source that tells the compiler that SLEEP is a procedure. Fortran 2015 provides an enhancement to the IMPLICIT statement that indicates that you want a diagnostic from the compiler when you reference a procedure via an identifier in this manner - you would either add an `IMPLICIT NONE (EXTERNAL)` statement to your source, or change the existing implicit statement to `IMPLICIT NONE (TYPE, EXTERNAL)`. But that's for the years ahead.
(If an intel/ex-intel J3 person is listening, the F2015 implicit none statement needs a constraint added to stop repetitions of a particular implicit-none-spec.)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks both of you. It makes thing clear. I have added the buildlog file for any inspection.
The question remains: I have not asked for a link to sleep. But Intel is so kind to give it to me without any asking from my side. The next standard seems to give the opportunity to let issue a warning. In the mean time: is there a MSVS option with which I can let the compilation / link fail (as a standard comforming program ought to do)?
Best regards,
Robert
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Robert van Amerongen wrote:
The question remains: I have not asked for a link to sleep. But Intel is so kind to give it to me without any asking from my side. The next standard seems to give the opportunity to let issue a warning. In the mean time: is there a MSVS option with which I can let the compilation / link fail (as a standard comforming program ought to do)?
If the program is standard conforming, then the compiler should accept it without too much complaint (otherwise the compiler's vendor will get complaints!).
If the program isn't standard conforming, then the compiler may complain, depending on the nature of the non-conformance.
In this case, the compiler doesn't know whether the program is non-conforming or not. Did the programmer intend to call the Intel provided SLEEP (or some other external procedure called SLEEP, that has been separately compiled) or not? The rules of the language permit implicit references to external procedures via identifiers that don't have the external attribute - something which a large majority of Fortran 77 source codes did.
You can add /link /nodefaultlib:libifport.lib to the command line and the linker will then ignore the the compiler provided directive to link against the library that provides SLEEP. In the absence of some other definition, you will then get an unresolved symbol error at link time. The equivalent property within a Visual Studio project is to put libifport.lib in the Linker > Input, Ignore Specific Library property. If you then, later, require different routines from that library, you will also get a link error, but you can always remove the nodefaultlib option, or specify the library explicitly as linker input.
(The name of libifport.lib may have changed with ifort version, but that's what it has been called for the last few releases at least.)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Here is a subroutine to insert a time-delay into an IVF program on Windows. This is probably more WinAPI and less "standard" Fortran than the OP is looking for, but it works perfectly, and blocks only the calling thread which is important for multithreaded programs where the intent is not to hang the entire system.
RECURSIVE SUBROUTINE delay_ms (howmany) USE kernel32, ONLY: WaitForSingleObject, CloseHandle, CreateEvent !sleep IMPLICIT NONE INTEGER, INTENT(IN) :: howmany INTEGER(HANDLE) :: hEvent INTEGER :: rval ! Win32 suspend function, allows the timeslice to be ! used by other threads until the timeout elapses IF (howmany <= 0) RETURN ! original method, seems to block all threads ! not just the calling thread !IF (howmany > 0) CALL sleep (howmany) ! new method, blocks only the calling thread hEvent = CreateEvent (NULL_SECURITY_ATTRIBUTES, & TRUE, & ! manual reset FALSE, & ! initial status NULL) ! unnamed event object rval = WaitForSingleObject (hEvent, howmany) rval = CloseHandle (hEvent) END SUBROUTINE delay_ms
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Again, thank you both.
I have tried to set the linker option with ignoring libifport.lib, but that does not give the required response. The file still exists with that name.
There is another option: use the Winapi function SleepEx. No interference with whatever Sleep function.
Paul's suggesting is very nice: I did not use it in a Multi threading environment and thus never realised the Sleep wil halt all threads!
Robert
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Sleep halting all threads in the process would surprise me - one of the uses of Sleep is to relinquish the time slice of the current thread so that other threads (in the same process or in other processes) can run.
Some simple testing here demonstrates that other threads in the process quite happily continue to execute while their colleagues are snoozing.
! Program that does a lot of sleeping, on different threads. ! ! Each thread loops, sleeping for some time then writing some ! output (a sequence of characters) directly to a character ! cell on the console. MODULE RatherSleepyMod USE IFWIN IMPLICIT NONE PRIVATE PUBLIC :: Run ! Nuber of threads, including main thread. INTEGER, PARAMETER :: num_threads = 24 ! Total time (approx) to run in ms. INTEGER, PARAMETER :: total_time = 10000 ! Attributes to draw output of the threads, cycled through by thread index. INTEGER(WORD), PARAMETER :: attributes(*) = [ & IANY([FOREGROUND_BLUE, FOREGROUND_INTENSITY]), & IANY([FOREGROUND_GREEN, FOREGROUND_INTENSITY]), & IANY([FOREGROUND_RED, FOREGROUND_INTENSITY]), & IANY([FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_INTENSITY]), & IANY([FOREGROUND_BLUE, FOREGROUND_RED, FOREGROUND_INTENSITY]), & IANY([FOREGROUND_GREEN, FOREGROUND_RED, FOREGROUND_INTENSITY]), & IANY([FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_RED, FOREGROUND_INTENSITY]) ] ! Number of cycles for the threads, cycled through by thread index. INTEGER, PARAMETER :: counts(*) = [ & 1, 10, 50, 100, 200, 500, 1000, 2000, 5000, 10000 ] ! Handle to the console output buffer. INTEGER(HANDLE) :: conout_handle ! Original console buffer info. TYPE(T_CONSOLE_SCREEN_BUFFER_INFO) :: original_buffer_info CONTAINS SUBROUTINE Run INTEGER(DWORD) :: thread_id INTEGER(DWORD) :: dwrc INTEGER(BOOL) :: brc INTEGER(HANDLE) :: thread_handles(2:num_threads) INTEGER :: i ! Get a handle to the console output buffer. conout_handle = GetStdHandle(STD_OUTPUT_HANDLE) ! Get the current cursor position so that we put the output somewhere ! that is likely visible to the user. brc = GetConsoleScreenBufferInfo(conout_handle, original_buffer_info) IF (brc == 0) THEN ERROR STOP 'stdout not attached to a console or other silliness' END IF IF (original_buffer_info%dwSize%Y < num_threads) THEN ERROR STOP 'Too many threads for console size' END IF ! Start the other threads. DO i = 1, num_threads IF (i /= 1) THEN thread_handles(i) = CreateThread( & NULL, & 0_DWORD, & LOC(thread_proc), & INT(i, LPVOID), & 0_DWORD, & LOC(thread_id) ) END IF END DO ! Do some work on the main thread too. CALL thread_proc(INT(1, LPVOID)) ! Wait for all the others to finish. dwrc = WaitForMultipleObjects( & SIZE(thread_handles, KIND=DWORD), & LOC(thread_handles), & TRUE, & INFINITE ) ! Clean up. DO i = 2, SIZE(thread_handles) brc = CloseHandle(thread_handles(i)) END DO END SUBROUTINE Run RECURSIVE SUBROUTINE thread_proc(idx) BIND(C) INTEGER(LPVOID), VALUE :: idx !DEC$ ATTRIBUTES STDCALL :: thread_proc INTEGER :: i CHARACTER :: c INTEGER :: my_count my_count = counts(MOD(idx - 1, SIZE(counts)) + 1) c = '0' CALL output_char(idx, c) DO i = 1, my_count CALL Sleep(INT(total_time / my_count, DWORD)) c = ACHAR(IACHAR('0') + MOD(i, 32)) CALL output_char(idx, c) END DO END SUBROUTINE thread_proc RECURSIVE SUBROUTINE output_char(idx, c) INTEGER(LPVOID), INTENT(IN) :: idx CHARACTER, INTENT(IN) :: c INTEGER(BOOL) :: brc TYPE(T_CHAR_INFO) :: buffer(1,1) TYPE(T_SMALL_RECT) :: write_region INTERFACE FUNCTION WriteConsoleOutput_but_better( hConsoleOutput, lpBuffer, & dwBufferSize, dwBufferCoord, lpWriteRegion ) & BIND(C, NAME='WriteConsoleOutputA') USE IFWINTY, ONLY: BOOL, HANDLE, T_CHAR_INFO, T_COORD, T_SMALL_RECT IMPLICIT NONE INTEGER(HANDLE), VALUE :: hConsoleOutput TYPE(T_CHAR_INFO), INTENT(IN) :: lpBuffer(*) TYPE(T_COORD), VALUE :: dwBufferSize TYPE(T_COORD), VALUE :: dwBufferCoord TYPE(T_SMALL_RECT), INTENT(INOUT) :: lpWriteRegion INTEGER(BOOL) :: WriteConsoleOutput_but_better !DEC$ ATTRIBUTES STDCALL :: WriteConsoleOutput_but_better END FUNCTION WriteConsoleOutput_but_better END INTERFACE buffer(1,:)%AsciiChar = c buffer(1,:)%Attributes = attributes(MOD(idx - 1, SIZE(attributes))+1) write_region%Left = idx - 1 write_region%Top = original_buffer_info%dwCursorPosition%Y write_region%Right = idx - 1 write_region%Bottom = original_buffer_info%dwCursorPosition%Y brc = WriteConsoleOutput_but_better( & conout_handle, & buffer, & T_COORD(SIZE(buffer, 1), SIZE(buffer, 2)), & T_COORD(0, 0), & write_region ) END SUBROUTINE output_char END MODULE RatherSleepyMod PROGRAM RatherSleepy USE RatherSleepyMod IMPLICIT NONE CALL Run END PROGRAM RatherSleepy
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@IanH -- I had initially used Sleep() in a program which is agressively multi-threaded with many simultaneous streams of serial communications. Sleep() seemed to work as advertised, until I added more threads of Winsock communications, whereupon Sleep() serialized the entire program. Changing from Sleep() to the event-based method made this problem go away. So a simple example where Sleep() seems to work proves only that simple examples can be simplistic, and there are far more subtle tests waiting to trip you up deep within Windows.
We (well, this programmer, at least) have neither knowledge nor control of how Sleep() is actually implemented, but we do understand what's going on by creating a non-signalled event which will never be signalled because it is not hooked up to anything, and hence WaitForSingleEvent() will return exactly as expected after its specified timeout. This appears to be thread-safe in all (mystery) contexts on the Windows side of the fence, as it better be because the WaitFor*Events() method is ubiquitous throughout Windows.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page