Изменение значения переменной, когда сигнал захвачен в Fortran


При разработке программы на Fortran, использующей некоторую итерационную процедуру, я столкнулся с необходимостью останавливать итерации вручную (чтобы выйти из цикла итераций без завершения программы).

Я решил сделать это, послав сигнал процессу. Я выбрал СИГАЛРМ. Я проверил, что он может быть пойман в ловушку без каких-либо неожиданных последствий.

При получении сигнала значение флага изменяется. Этот флаг проверяется внутри цикла итерации и завершается, если флаг имеет значение true. Пример такого кода приведен ниже.

!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" локальной при таком уровне оптимизации? И что я могу сделать, чтобы заставить его работать правильно?

Заранее благодарю. MuKeP.

1 2

1 ответ:

Как ответил Лорри (к сожалению, этот краткий, но правильный ответ был удален неверно направленными отзывами) - попробуйте атрибут volatile на toStopIteration. Это говорит компилятору, что переменная может быть переопределена чем-то другим, в противном случае из источника, видимого компилятору, похоже, что значение этой переменной не может измениться в итерации, и поэтому нет смысла проверять ее каждую итерацию.