首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Unified Parallel C 中的集体函数-1

Unified Parallel C 中的集体函数-1

集体函数概述Unified Parallel C 是支持多线程的并行编程语言,提供了集体函数来简化并行程序中所有线程所要执行的共同操作。集体函数,顾名思义,是必须为每个线程执行的函数,否则会报错。集体函数按照功能可以分为两类:数据位置移动集体函数和数据计算集体函数。
集体函数参数与同步方式集体函数的内存语义控制集体函数同步的方式。头文件 upc.h 定义了整形类型 upc_flag_t,该类型控制着一些集体函数的同步方式。类型为 upc_flag_t 的函数参数的值等于对 UPC_IN_XSYNC 和 UPC_OUT_YSYNC 两个操作数进行按位或(|)操作的结果,也就是说类型为 upc_flag_t 的函数参数的值为(UPC_IN_XSYNC | UPC_OUT_YSYNC),其中 X 和 Y 的值可以是 NO、 MY、或者 All。
UPC_IN_XSYNCUPC_IN_XSYNC 参数控制输入数据的同步模式:
如果 X 的值为 NO, 当第一个线程调用集体函数的时候,该函数即开始读或者写。
如果 X 的值为 MY, 当与数据具有亲缘关系的线程调用集体函数的时候,该函数即开始读或者写。该函数对除当前线程之外的所有线程进行同步
如果 X 的值为是 ALL, 只有当所有线程调用集体函数,该函数才能开始读或者写。该函数对所有的数据进行同步。通过参数 UPC_IN_ALLSYNC,函数确保所有线程在调用这个函数之后,读到相同的输入数据。
UPC_OUT_YSYNCUPC_OUT_YSYNC 参数控制输出数据的同步模式:
如果 Y 的值是 NO, 在最后一个线程完成对集体函数的调用,函数即可以读或者写。函数不对数据进行同步。
如果 Y 的值是 MY, 只有对与线程具有亲缘关系的数据的读与写操作全部完成之后,函数才能在该线程中返回。通过 UPC_OUT_MYSYNC,在一个线程调用函数返回之后,函数确保这个线程读到与该线程具有亲缘关系的最新的输出数据。
如果 Y 的值是 All, 只有在对数据的读和写操作完成之后,函数才能返回。通过 UPC_OUT_ALLSYNC, 在一个线程从函数调用返回之后,确保线程读到最新的输出数据。
数据位置移动集体函数upc_all_broadcast
作用:将与一个线程具有亲缘关系的一块共享内存,复制到每个线程的共享内存。
函数原型:
1
2
void upc_all_broadcast(shared void * restrict dst, shared const void * restrict src,\
    size_t nbytes, upc_flag_t flags);




参数:
dst:一个指向内存复制目标地址的指针。
src:一个指向被复制数据地址的指针。
nbytes: 代表所要复制数据块大小为多少字节。
flags: 控制函数的同步模式。
下面程序通过 upc_all_broadcast 函数将共享数组 A 的元素复制到共享数组 B 中。
清单 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# include <upc.h>
# include <upc_collective.h>
# include <stdio.h>

# define NELEMS 4
# define FAILURE 1
# define SUCCESS 0

shared[] int A[NELEMS]; // 要被复制的共享数据
shared[NELEMS] int B[NELEMS*THREADS]; // 目标数据

int main()
{
  int i=0;

  // 对共享数组 A 进行初始化
  upc_forall(i=0;i<NELEMS;i++;&A)
  {
    A=i;
  }
  upc_all_broadcast(B,A,sizeof(int)*NELEMS,UPC_IN_ALLSYNC|UPC_OUT_NOSYNC);
  upc_barrier;

  // 验证结果
  for(i=0;i<NELEMS; i++)
  {
    if(B[MYTHREAD*NELEMS+i] !=i)
    {
      printf("Error: thread %d,B[%d]=%d,expect: %d\n",MYTHREAD,i,B[MYTHREAD*
      NELEMS+i],i);
      upc_global_exit(FAILURE); /*结束所有线程,强制退出程序*/
    }
  }
  return SUCCESS;
}




upc_all_scatter
作用:将与一个线程具有亲缘关系的第 i 块内存,复制到与第 i 个线程具有亲缘关系的一块共享内存。
函数原型:
1
2
void upc_all_scatter(shared void * restrict dst, shared const void * restrict src, \
size_t nbytes, upc_flag_t flags);




dst:一个指向内存复制目标地址的指针。
src:一个指向要被复制数据地址的指针。
nbytes:代表所要复制数据块大小为多少字节。
flags: 控制函数的同步模式。
下面程序通过 upc_all_scatter 将共享数组 A 的元素区块分别散发到共享数组 B 中。
清单 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# include <upc_collective.h>
# include <stdio.h>

# define NELEMS 10
# define FAILURE 1
# define SUCCESS 0

shared[] int *shared A; // src 指针
shared[NELEMS] int B[NELEMS*THREADS]; // dst 指针

int main()
{
  int i=0;

  // 线程 THREADS-1 动态地为线程 THREADS-1 分配共享内存
  if(MYTHREAD == THREADS -1)
  A=(shared[] int *)upc_alloc(THREADS*NELEMS*sizeof(int));
  upc_barrier;
   
  // 对 A 进行初始化
  upc_forall(i=0;i<NELEMS*THREADS;i++;A+i)
  A=i;
  upc_all_scatter(B,A,sizeof(int)*NELEMS,UPC_IN_ALLSYNC|UPC_OUT_ALLSYNC);

  // 校验结果
  for(i=0;i<NELEMS*THREADS;i++)
  if(B != i)
  {
    printf("Error: thread=%d,B[%d]=%d,expect=%d\n",MYTHREAD,i,B,i);
    upc_global_exit(FAILURE); // 结束所有线程,强制程序退出
  }
  return SUCCESS;
}




upc_all_gather
作用:从与第 i 个线程具有亲缘关系的共享内存中,复制一块内存到与一个线程具有亲缘关系的第 i 块内存。
函数原型:
1
2
void upc_all_gather(shared void * restrict dst, shared const void * restrict src, \
size_t nbytes, upc_flag_t flags);




参数:
dst:一个指向内存复制目标地址的指针。
src:一个指向要被复制数据地址的指针。
nbytes:代表所要复制数据块大小为多少字节。
flags:控制函数的同步模式。
下面程序通过 upc_all_gather 将共享数组 A 中的各个元素区块集中到共享数组 B 中。
清单 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# include <upc.h>
# include <upc_collective.h>
# include <stdio.h>

# define NELEMS 10
# define FAILURE 1
# define SUCCESS 0

shared[NELEMS] int A[NELEMS*THREADS]; // src 指针
shared[] int B[NELEMS*THREADS];         // dst 指针

int main()
{
  int i=0;

  // 对 A 进行初始化
  upc_forall(i=0;i<NELEMS*THREADS; i++; &A)
  A=i;
  upc_all_gather(B,A,sizeof(int)*NELEMS,UPC_IN_ALLSYNC|UPC_OUT_NOSYNC);
  upc_barrier;

  // 校验结果
  for(i=0;i<NELEMS*THREADS;i++)
  if(B != i)
  {
    printf("Error: thread=%d,B[%d]=%d,expect=%d\n",MYTHREAD,i,B,i);
    upc_global_exit(FAILURE); // 结束所有线程,强制程序退出
  }
  return SUCCESS;
}




upc_all_gather_all
作用:复制与第 i 个线程具有亲缘关系的一块内存到每个线程的第 i 块共享内存。
函数原型:
1
2
void upc_all_gather_all(shared void * restrict dst, shared const void * restrict src,
\size_t nbytes, upc_flag_t flags);




参数:
dst:一个指向内存复制目标地址的指针。
src:一个指向要被复制数据地址的指针。
nbytes:代表所要复制数据块大小为多少字节。
flags:控制函数的同步模式。
下面程序通过 upc_all_gather_all 将共享数组 A 中所有的元素区块复制到位于每一个线程内的共享数组 B 的数据区块中。
清单 4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# include <upc.h>
# include <upc_collective.h>
# include <stdio.h>
# define NELEMS 10
# define FAILURE 1
# define SUCCESS 0

shared[NELEMS] int A[NELEMS*THREADS];
shared[NELEMS*THREADS] int B[THREADS][NELEMS*THREADS];

int main()
{
  int i=0;

  // 对 A 进行初始化
  upc_forall(i=0;i<NELEMS*THREADS;i++;&A)
  A=i;
  upc_barrier; // 在调用集体函数之前对数据进行同步
  upc_all_gather_all(B,A,sizeof(int)*NELEMS,UPC_IN_NOSYNC|UPC_OUT_NOSYNC);
  upc_barrier; // 对所有线程进行同步,确保每个线程完成复制的操作

  // 校验结果
  for(i=0;i<NELEMS*THREADS;i++)
  if(B[MYTHREAD] != i)
  {
    printf("Error: thread=%d,B[%d][%d]=%d,expect=%d\n",MYTHREAD,MYTHREAD,i,
    B[MYTHREAD],i);
    upc_global_exit(FAILURE); // 结束所有线程,强制退出程序
  }
  return SUCCESS;
}




upc_all_exchange
作用:从与线程 j 具有亲缘关系的共享内存里,复制第 i 块内存到与线程 i 具有亲缘关系的第 j 块内存。
函数原型:
1
2
void upc_all_exchange(shared void * restrict dst, shared const void * restrict
src, size_t nbytes, upc_flag_t flags);




参数:
dst:一个指向内存复制目标地址的指针。
src:一个指向要被复制数据地址的指针。
nbytes:代表所要复制数据块大小为多少字节。
flags:控制函数的同步模式。
返回列表