【问题标题】:Fortran call to sleep does not block programFortran 调用睡眠不会阻塞程序
【发布时间】:2020-08-12 12:15:23
【问题描述】:

我有最基本的 Fortran 程序:

program sleep
    print*, "Sleeping"
    call sleep(30)
    print*, "Done"
end program sleep

我使用gfortran sleep.f90(版本 9.3.0)编译。根据我从sleep 文档中了解到的情况,该程序应该休眠 30 秒,即我应该期望在“休眠”后 30 秒看到“完成”打印。这不会发生:我看到两个打印语句都立即出现,这表明 call sleep(30) 不会以任何方式阻止我的程序。做call sleep(10000) 没有任何区别。我正在 Linux 的 Windows 子系统 (WSL Ubuntu 20.04) 上编译和运行这个程序。

【问题讨论】:

  • 您使用什么操作系统?试试30000 甚至30000000,会发生什么?
  • @roygvib 这个问题似乎与您链接的第一个问题(关于 WSL 上的睡眠)有关。我已经用Python solution 替换了/usr/bin/sleep,但不幸的是这不会传播到我的代码中。 Fortran 是否在内部使用/usr/bin/sleep?我可以在 Fortran 中以某种方式重载对 sleep 的调用吗?
  • 我认为 Fortran 使用/usr/bin/sleep,而是使用一些特定于编译器的库例程。那么,要使用 Python 脚本,也许我们可以使用 call system( "sleep.py 7" ) 等? (其中sleep.py 是链接中显示的 Python 脚本。)这似乎适用于我的 mac...
  • gfortran 不使用 /usr/bin/sleep。对于您的代码,您可以使用 -fdump-tree-original 选项生成中间代码,这表明 gfortran 调用了库例程 _gfortran_sleep_i4_sub。在真正的类 Unix 操作系统上,此例程调用 sleep(3),它是 C 标准库的一部分。

标签: fortran gfortran windows-subsystem-for-linux


【解决方案1】:

所以这个问题是通过@roygvib 在 cmets 中提出的解决方案组合解决的。主要问题是 WSL (Ubuntu 20.04) 环境中的sleep 已损坏。第一步是将坏掉的/usr/bin/sleep替换成this Python script

#!/usr/bin/env python3

import sys
import time

time.sleep(int(sys.argv[1]))

然后,修改 Fortran 程序以使 system 调用这个新的 sleep 可执行文件:

program sleep
    print*, "Sleeping"
    call system("sleep 30")
    print*, "Done"
end program sleep

在 WSL 的下一次更新之前,这个 hack 必须要做。

【讨论】:

  • 看起来像 nanosleep 中的问题(在可执行文件上使用 strace)。在 18.04 它等待并返回 0,在 20.04 它返回无效参数。
  • 不同之处在于 18.04 使用 nanosleep 而 20.04 使用 clock_nanosleep。 clock_nanosleep 问题在stackoverflow.com/questions/62747896/… 中讨论。如果您在 WSL 上退回到 Ubuntu 18.04,您的原始程序将可以运行。
【解决方案2】:

sleep 过程不是 Fortran 标准的一部分并且不可移植。下面是一个解决方案,它可能适用于所有具有任何符合标准的 Fortran 编译器的系统:

module sleep_mod

    use, intrinsic :: iso_fortran_env, only: IK => int64, RK => real64, output_unit
    implicit none

contains

    subroutine sleep(seconds)

        implicit none

        real(RK), intent(in) :: seconds ! sleep time
        integer(IK)          :: countOld, countNew, countMax
        real(RK)             :: countRate

        call system_clock( count=countOld, count_rate=countRate, count_max=countMax )
        if (countOld==-huge(0_IK) .or. nint(countRate)==0_IK .or. countMax==0_IK) then
            write(output_unit,"(A)") "Error occurred. There is no processor clock."
            error stop
        end if

        countRate = 1._RK / countRate
        do
            call system_clock( count=countNew )
            if (countNew==countMax) then
                write(output_unit,"(A)") "Error occurred. Maximum processor clock count reached."
                error stop
            end if
            if ( real(countNew-countOld,kind=RK) * countRate > seconds ) exit
            cycle
        end do

    end subroutine sleep

end module sleep_mod

program main
    use sleep_mod, only: output_unit, sleep, RK
    implicit none
    write(output_unit,"(A)") "Sleep for 5 second."
    call execute_command_line(" ") ! flush stdout
    call sleep(seconds = 5._RK)
    write(output_unit,"(A)") "Wake up."
end program main

您可以在这里在线测试:https://www.tutorialspoint.com/compile_fortran_online.php

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-18
    • 2011-07-23
    • 2011-02-25
    • 2015-03-18
    • 1970-01-01
    • 2018-02-18
    相关资源
    最近更新 更多