2017-06-27 62 views
2

只要程序不允许同时写入存储在模块中的共享数据结构的相同元素,它是否是线程安全的?我知道这是一个noob问题,但无法在任何地方明确地找到它。这里的情况:正在读/写模块数组的不同元素线程安全吗?

在节目开始时,数据被初始化并存储在模块级分配数组(FIELDVARS),然后变成到该模块由USE声明中引用的任何子程序访问。

现在假设程序进入多线程和/或多核计算阶段,并且在重复多次同时调用子例程(COMPUTE)期间访问“读取/写入”操作。

计算阶段完成后,程序返回到单线程阶段,并且必须在后续子例程(POST)中使用FIELDVARS。但是,FIELDVARS不能被添加到COMPUTEPOST的输入参数中,因为它们是从闭源程序主程序中调用的。因此,模块级数组用于在子程序之间传递addt'l数据。

假设FIELDVARSCOMPUTE已经被设计成每次调用COMPUTE总是会给访问一组的FIELDVARS独特的元素,这些都保证比任何其他呼叫不同的,所以同时“写”操作在相同元素将永远不会发生。例如:

[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ... ] <-- FIELDVARS 
    ^---call 1---^ ^---call 2---^ ... <-- Each call to COMPUTE is guaranteed to access a specific set of elements of FIELDVARS. 

问:是此方案被认为是“线程安全”,“有条件安全”或“不是线程安全”?如果它不安全,那么具体的危险是什么,你会建议如何处理它?

其他相关细节:

  • 主程序控制线程。
  • 主程序的源代码不可用,也不能更改。
  • 主程序控制如何/何时调用COMPUTE,POST和其他子例程,以及可以传入哪些参数。这就是为什么模块级数组用于在不同子例程之间传递数据的原因,而不是作为ARG。

! DEMO MODULE W/ ALLOCATABLE INTEGER ARRAY 
module DATA_MODULE 
    integer, dimension(:), allocatable :: FIELDVARS !<-- allocated/populated elsewhere, prior to calling COMPUTE 
end module DATA_MODULE 

! DEMO COMPUTE SUBROUTINE (THREADED PHASE W/ MULTIPLE SIMULTANEOUS CALLS) 
subroutine COMPUTE(x, y, x_idx, y_idx, flag) 
    use DATA_MODULE 
    logical :: flag 
    integer :: x,y,x_idx,y_idx     !<-- different for every call to COMPUTE 
    if (flag == .false.) then     !<-- read data only 
    ... 
    x = FIELDVARS(x_idx) 
    y = FIELDVARS(y_idx) 
    ... 
    else if (flag == .true.) then    !<-- write data 
    ... 
    FIELDVARS(x_idx) = 0 
    FIELDVARS(y_idx) = 0 
    ... 
    endif 
end subroutine COMPUTE 
+0

刚发现这个类似的问题[写入不同线程的相邻数组元素](https://stackoverflow.com/q/5380438/7038689),这似乎表明它通常被认为是安全的(虽然评论者提到它可能在旧的cpu架构上不安全)。 –

回答

3

这是罚款和许多程序依赖于这个事实。在OpenMP中,您经常循环使用数组,而不同的线程可以轻松处理内存中彼此接近的元素,尤其是在分配给每个线程的块的边界上。

在现代的CPU这是一个没有问题。又见https://en.wikipedia.org/wiki/Cache_coherence

什么是真正的问题是False sharing。与属于相同chache行的内存元素一起工作的两个或更多线程将编译共享资源,并且可能非常慢。

+0

感谢您的额外链接。 –

相关问题