将数组保存到文件 - 分段错误

时间:2014-03-19 12:39:31

标签: arrays segmentation-fault fortran

我想在两个程序之间共享数组中的数据。在another question中,我被建议使用未格式化的文件,但尝试此操作时遇到问题。

当我加入

OPEN(UNIT=10,FILE='all_paths.direct',FORM='UNFORMATTED', ACCESS='sequential', STATUS='unknown') 

在代码中,我得到了分段错误?

编辑:这是程序:

    PROGRAM POSS_PATHS

    use omp_lib

    IMPLICIT NONE

    INTERFACE
    RECURSIVE SUBROUTINE bridge(start, goal, combined, a, b, interm, first)
        USE hash_integer
        USE locs_table

        IMPLICIT NONE

        INTEGER, DIMENSION(1:2), INTENT(IN)                         :: start, goal
        INTEGER, DIMENSION(:,:), INTENT(INOUT)                        :: combined
        INTEGER, DIMENSION(100), INTENT(INOUT)                      :: interm
        INTEGER, INTENT(INOUT)                                      :: a
        INTEGER, INTENT(IN)                                         :: b
        INTEGER                                                     :: c
        INTEGER                                                     :: i, k, j
        INTEGER, DIMENSION(1:2)                                     :: remainder, exact
        INTEGER, DIMENSION(1:6)                                     :: next, dflt
        LOGICAL, INTENT(IN)                                         :: first   
    END SUBROUTINE bridge

    END INTERFACE


    INTEGER, DIMENSION(1:8)                                 :: beginning, ending
    INTEGER, DIMENSION(1:2)                                 :: start, goal
    INTEGER, DIMENSION(100, 300000)                         :: combined
    INTEGER, DIMENSION(100)                                 :: interm
    INTEGER                                                 :: i, j, k, l, a, b


    OPEN(UNIT=33, FILE='all_paths', FORM='UNFORMATTED', ACCESS='sequential', STATUS='unknown')


    DATA (beginning(i), i=1, 7) / 1, 2, 3, 4, 5, 6, 7 /
    DATA (ending(i), i=1, 8) / 217, 225, 226, 227, 228, 231, 232, 233 /

    a = 0
    !$omp parallel
    !$omp do       
    DO i=1, 7
        DO j = 1, 7
            DO k = 1, 8
                DO l = 1, 8
                    a = a + 1
                    b = 1
                    start(1) = beginning(i)
                    start(2) = beginning(j)
                    goal(1) = ending(k)
                    goal(2) = ending(l)
                    combined(1:2,a) = start

                    CALL bridge(start, goal, combined, a, b, interm, .TRUE.)

                END DO
            END DO
        END DO
    END DO


    !$omp end do
    !$omp end parallel

    WRITE(33, '(100I3)') combined

    CLOSE(UNIT=10)

END PROGRAM


RECURSIVE SUBROUTINE bridge(start, goal, combined, a, b, interm, first)
    USE hash_integer
    USE locs_table

    IMPLICIT NONE

    INTEGER, DIMENSION(1:2), INTENT(IN)                         :: start, goal
    INTEGER, DIMENSION(:,:), INTENT(INOUT)                        :: combined
    INTEGER, DIMENSION(100), INTENT(INOUT)                      :: interm
    INTEGER, INTENT(INOUT)                                      :: a
    INTEGER, INTENT(IN)                                         :: b
    INTEGER                                                     :: c
    INTEGER                                                     :: i, k, j
    INTEGER, DIMENSION(1:2)                                     :: remainder, exact
    INTEGER, DIMENSION(1:6)                                     :: next, dflt
    LOGICAL, INTENT(IN)                                         :: first                       

    remainder(1)= mod(start(1),8)
    exact(1) = start(1) / 8

    remainder(2) = mod(start(2),8)
    exact(2) = start(2) / 8

    DATA (dflt(i), i=1, 6) / 1000, 1000, 1000, 1000, 1000, 1000 /


    c = b + 2


    CALL hash_get(remainder, next, dflt)

    DO k=1, 6, 2
        next(k) = next(k)+(exact(1)*8)
        next(k+1) = next(k+1)+(exact(2)*8)

        IF((next(k) > goal(1) .AND. next(k+1) > goal(2)) .OR. next(k) > 233 .OR. next(k+1) > 233) THEN
            CYCLE
        END IF

        interm(c:c+1) = next(k:k+1)


        IF (next(k) == goal(1) .AND. next(k+1) == goal(2)) THEN
            combined(1:c+1,a) = interm(1:c+1)
            a = a + a

        ELSE IF (next(k) > goal(1) .OR. next(k+1) > goal(2)) THEN
            IF (first) THEN
                CALL bridge(next(k:k+1), goal, combined, a, c, interm, .FALSE.)
            ELSE
                CYCLE
            END IF
        ELSE
            CALL bridge(next(k:k+1), goal, combined, a, c, interm, .TRUE.)
        END IF


    END DO


END SUBROUTINE bridge

在另一个测试程序中使用相同的开始语句不会导致段错误

2 个答案:

答案 0 :(得分:4)

此声明

INTEGER, DIMENSION(100, 300000) :: combined

可能会超出平台对静态数组的限制。代码将编译,但是一旦程序开始执行,运行时将在绝望中抛出,这看起来好像它发生在第一个可执行语句中。但open语句不会导致分段错误,试图获取更多堆栈(我认为)比平台提供的(默认情况下)是这里的问题。

一种选择是调整编译器选项和环境设置,有关详细信息,请参阅平台文档。另一种选择是制作数组allocatable

INTEGER, DIMENSION(:,:), ALLOCATABLE :: combined

并在运行时分配它。

如果你这样做,你会发现执行该行的运行时阻碍

WRITE(33, '(100I3)') combined

您尝试将格式化输出写入为未格式化输出打开的文件。

答案 1 :(得分:0)

该代码中存在许多与OpenMP相关的错误。由于差的变量共享属性导致的数据访问越来越多,可能会发生分段错误。 jkl用作私有循环计数器但未声明为私有,因此可能达到高于循环上限值的值,并且从beginning读取垃圾ending个数组。另外a的增量不受ATOMIC构造的保护,更不用说bridge似乎也修改了astartgoal也必须是私密的。

首先修复jkl的共享属性:

!$omp parallel do private(j,k,l,b,aa,start,goal)
DO i=1, 7
    DO j = 1, 7
        DO k = 1, 8
            DO l = 1, 8
                !$omp atomic capture
                a = a + 1
                aa = a
                !$omp end atomic
                b = 1
                start(1) = beginning(i)
                start(2) = beginning(j)
                goal(1) = ending(k)
                goal(2) = ending(l)
                combined(1:2,aa) = start  ! aa holds the captured value of a

                CALL bridge(start, goal, combined, aa, b, interm, .TRUE.)

            END DO
        END DO
    END DO
END DO
!$omp end parallel do

我不确定bridge如何修改a的值以及它在每次迭代中如何与递增a进行交互,但在上面的代码中捕获了值在一个私有变量中,这可能不是你想要的。如果重要的是a返回的bridge的修改值应该在下一次迭代中使用,那么最内层循环的整个主体应该放在critical构造中。这有效地使代码串行 - 这种算法几乎不可并行。