问题 在Fortran睡觉


有没有人知道在Fortran中以一定的毫秒数睡眠的方法?我不想使用非便携式系统调用,因此Fortran或C库固有的任何内容都是首选。


3298
2017-08-03 19:04


起源

有一个'sleep'子例程,它需要几秒作为参数,但我不确定它来自哪里(包装到C函数?)。它似乎适合我的意图。我在PC上使用英特尔Fortran编译器12。 - Brian Triplett
我刚刚遇到一个使用(非标准)调用系统(char_arg)的Fortran程序,该系统访问没有CPU开销的系统。用pgf90,ifort和gfortran试了一下,一切都很好。因此,可以执行诸如调用系统('sleep'// number_of_seconds_string)之类的操作来获取睡眠功能。没有机会与其他编译器一起测试。 - milancurcic


答案:


使用Fortran ISO C绑定使用C库睡眠以秒为单位进行睡眠:

   module Fortran_Sleep

   use, intrinsic :: iso_c_binding, only: c_int

   implicit none

   interface

      !  should be unsigned int ... not available in Fortran
      !  OK until highest bit gets set.
      function FortSleep (seconds)  bind ( C, name="sleep" )
          import
          integer (c_int) :: FortSleep
          integer (c_int), intent (in), VALUE :: seconds
      end function FortSleep

   end interface

end module Fortran_Sleep


program test_Fortran_Sleep

   use, intrinsic :: iso_c_binding, only: c_int

   use Fortran_Sleep

   implicit none

   integer (c_int) :: wait_sec, how_long

   write (*, '( "Input sleep time: " )', advance='no')
   read (*, *) wait_sec
   how_long = FortSleep ( wait_sec )

   write (*, *) how_long

   stop

end program test_Fortran_Sleep

9
2017-08-03 19:36



您认为英特尔Fortran内部提供的“睡眠”功能基本上与您上面提供的相同吗? - Brian Triplett
是的,功能上可能是一样的。 gfortran中提供了类似的子程序。这是一个可能不属于某些其他编译器的扩展。 - M. S. B.
嗨,在Linux中,我可以使用它,它工作正常。在Windows中并使用MinGW,在编译时会抱怨它找不到Sleep功能。你知道怎么解决这个问题吗? - Hossein Talebi
此解决方案不能跨操作系统移植。 (我相信,只有* nix。)@milancurcic下面的答案应适用于所有操作系统。 - zbeekman


您可以使用Fortran标准内部函数来执行此操作而无需C绑定:

program sleep
!===============================================================================
implicit none
character(len=100) :: arg ! input argument character string
integer,dimension(8) :: t ! arguments for date_and_time
integer :: s1,s2,ms1,ms2  ! start and end times [ms]
real :: dt                ! desired sleep interval [ms]
!===============================================================================
! Get start time:
call date_and_time(values=t)
ms1=(t(5)*3600+t(6)*60+t(7))*1000+t(8)

! Get the command argument, e.g. sleep time in milliseconds:
call get_command_argument(number=1,value=arg)
read(unit=arg,fmt=*)dt

do ! check time:
  call date_and_time(values=t)
  ms2=(t(5)*3600+t(6)*60+t(7))*1000+t(8)
  if(ms2-ms1>=dt)exit
enddo
!===============================================================================
endprogram sleep

假设可执行文件是slp:

~$ time slp 1234

real        0m1.237s
user        0m1.233s
sys         0m0.003s 

如果您担心它会在午夜时分破坏,请在此程序中添加一个特殊情况:)


5
2017-08-04 04:31



这使我想起。如果在睡眠期间需要cpu时间,绝对不应该使用这种方法。我假设你没有长时间等待远程数据。如果你这样做,你最好使用shell包装器,因为上面的例子是cpu密集型的。 - milancurcic
这个答案肯定比接受的答案更便携。 - zbeekman
它是 略 更便携,但它正在忙着等待,没有正确的睡眠,所以接受的答案是正确的接受。 - Vladimir F


      ! This is another option of making your fortran code to wait for x seconds
       Integer :: iStart, iNew
       Real*8 :: rWait, rDT
      ! rWait: seconds that you want to wait for; you can also set this as an (IN)
      ! variable if this code goes into a subroutine that is developed to be called 
      ! from any part of the program.
      rWait = 1.d0; rDT = 0.d0
      call system_clock (iStart)
      do while (rDT <= rWait)
          call system_clock (iNew)
          rDT = floatj (iNew - iStart) / 10000.d0
      enddo

-1
2017-08-19 20:34



system_clock仍然是不可移植的。它可能在不同的系统/不同的编译器上表现不同。 看看这个答案了。 - Dan Sp.
它是便携式的,但是必须查询时钟速率并使用它获得的值。而且,这只是 忙着做  en.wikipedia.org/wiki/Busy_waiting,不适当的睡觉。 - Vladimir F