在 Fortran 上开发程序时,采用了一些迭代过程,我面临着手动停止迭代的必要性(在不终止程序的情况下退出迭代循环)。
我决定向进程发送信号。我选择了SIGALRM。我已经检查过它可以被困住而不会产生任何意外后果。
当收到信号时,标志值会改变。在迭代循环内检查此标志,如果标志为真则退出。下面给出了此类代码的示例。
!file mymod.f90
module mymod
use ifport
integer*4 :: err
integer*4 :: SIGNSET
integer*4, parameter :: mySignal=14
logical*1 :: toStopIteration
contains
! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !
integer*4 function setTrap() result(ret)
implicit none
call PXFSTRUCTCREATE('sigset',SIGNSET,err)
call PXFSIGADDSET(SIGNSET,mySignal,err) !add my signal to the set.
ret=0; return
end function setTrap
! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !
integer*4 function onTrap(sig_num) result(rcode)
implicit none
integer*4 :: sig_num,err
rcode=0
select case (sig_num)
case(mySignal)
write (*,*) 'Signal occurred. Stop iteration called'
write (*,*) 'flag: ',toStopIteration
toStopIteration=.true.
write (*,*) 'flag: ',toStopIteration
rcode=1
return
case (SIGINT) ; stop
case (SIGTERM); stop
case (SIGABRT); stop
end select
end function onTrap
! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !
end module mymod
!file main.f90
program main
use mymod
implicit none
integer*4 :: i,j,N,Niters,sum1
err=setTrap()
err=signal(mySignal, onTrap, -1)
toStopIteration=.false.
open (1,file='output')
write (*,*) 'PID=',getpid()
write (1,*) 'Outside',toStopIteration
N=5000000; Niters=100000
do i = 1,Niters
if (toStopIteration) then
toStopIteration=.false.
exit
endif
sum1=0
do j = 1,N
sum1=sum1+j
enddo
write (1,*) i,toStopIteration,sum1
enddo
write (*,*) 'Procedure was terminated due to signal received. The last iteration was', i
write (*,*) 'Now I will do other job for you.'
stop
end program main
应用程序是使用 ifort 编译的:ifort -c -O2 -traceback
。
当我向进程 kill -14 pid
发送信号时,
我将输出输出到终端:
Signal occurred. Stop iteration called
flag: F
flag: T
但是迭代循环仍在运行,并且如文件中所写,变量“toStopIteration”等于 false。
偶然间,我发现当使用-O0 -traceback
参数编译时,它工作得很好。
为什么会发生这种情况?在这样的优化级别下,变量“toStopIteration”是否会成为局部变量?我该怎么做才能使其正常工作?
提前致谢。 穆克P。
最佳答案
正如 Lorri 的回答(不幸的是,这个简洁但正确的答案已被错误的评论删除) - 尝试 toStopIteration 上的 volatile 属性。这告诉编译器该变量可能会被其他东西重新定义,否则从编译器可见的源来看,该变量的值在迭代中无法更改,因此每次迭代都没有必要测试它。
关于fortran - Fortran 中信号被捕获时更改变量值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45942492/