Fortran中的睡眠函数

20

有没有办法在Fortran中等待给定毫秒数的休眠呢?我不想使用非可移植的系统调用,所以最好使用Fortran或C库中的任何内部函数。


有一个“sleep”子程序,它以秒数作为参数,但我不确定它是从哪里来的(C函数的包装器?)。对于我的意图,它似乎工作得很好。我在PC上使用Intel Fortran Compiler 12。 - Brian Triplett
我刚刚发现了一个Fortran程序,它使用了一个(非标准的)调用system(char_arg)的方法来访问系统,没有CPU开销。我已经用pgf90、ifort和gfortran测试过了,都可以正常运行。因此,我们可以像这样做:call system('sleep '//number_of_seconds_string) 来获得一个睡眠函数。我还没有机会用其他编译器测试这个方法。 - milancurcic
我认为 @BrianTriplett 提到的 sleep 子程序是 GNU 扩展,所以我不知道它是否符合可移植性的要求。 - Manuel Pena
3个回答

15

使用Fortran ISO C绑定来使用C库中的sleep函数以秒为单位进行睡眠:

   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

你认为Intel Fortran内置的“sleep”函数基本上与你上面提供的功能相同吗? - Brian Triplett
是的,功能可能是相同的。gfortran 中有一个类似的子程序可用。这是一个扩展,可能不是其他编译器的一部分。 - M. S. B.
1
嗨,在Linux中我可以使用这个,它很好用。在Windows和使用MinGW时,编译时会抱怨找不到Sleep函数。你知道如何解决这个问题吗? - Hossein Talebi
这个方案不能跨操作系统移植(我相信这只在*nix上可以)。@milancurcic 在下面的答案应该适用于所有操作系统。 - zbeekman

4

您可以使用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 

如果你担心这个程序在午夜时会出现问题,可以添加一个特殊情况。 :)

4
这让我想起来,如果你在睡眠期间需要使用CPU时间,那么绝对不应该使用这种方法。我假设你不是长时间等待远程数据,如果是的话,最好使用一个shell包装器,因为上面的例子需要大量的CPU资源。 - milancurcic
这个答案肯定比被接受的答案更具可移植性。 - zbeekman
4
它稍微更加便携,但它是繁忙等待而不是适当的睡眠,因此被接受的答案是正确的。 - Vladimir F Героям слава
这是忙等待,这不能真正被视为睡眠。 - Shriraj Hegde

-1
      ! 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

2
system_clock仍然不可移植。在不同的系统/编译器上可能会有不同的行为。查看这个答案。 - Dan Sp.
1
它是可移植的,但必须查询时钟速率并使用获得的值。此外,这只是“忙等待”https://en.wikipedia.org/wiki/Busy_waiting,并非适当的睡眠。 - Vladimir F Героям слава

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接