2017-08-29 86 views
2

在Fortran上开发程序时,使用某种迭代过程时,我面临必须手动停止迭代(从程序终止时退出迭代循环)的必要性。在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”等于假。

不小心,我发现用-O0 -traceback参数编译时,它工作正常。 为什么会发生?变量“toStopIteration”是否具有这样的优化级别?我能做些什么才能使它正常工作?

在此先感谢。 MuKeP。

+0

对于所有人来说,谁会找到这个问题并且需要详细信息。您需要使用'logical * 1,volatile :: toStopIteration'语句。但正如我理解的那样,它是2003年Fortran标准中出现的一个特征。 – MuKeP

回答

2

由于Lorri回答(不幸的是,简洁但正确的答案已被错误的评论删除) - 尝试toStopIteration上的volatile属性。这告诉编译器该变量可能被别的东西重新定义,否则从可见源到编译器的源看起来,该变量的值在迭代中不能改变,因此每次迭代都没有意义。

+0

非常感谢您的帮助。它解决了我的问题。也许我更好地阅读规范更准确:)。 – MuKeP