下面通过一个具体的 UPC 程序的例子来更好地理解 UPC 语言 . 这个例子是通过 upc_forall 语句对线程进行分工,计算出所给数组 A 所有元素之和。程序输出如图 8 所示。
清单 5. UPC 程序例子
#include <upc.h> // 假定设定 4 个线程来执行这个程序 # define N 10000 shared int A[N]; shared int sum=0; shared int partialsum[THREADS]={0}; /* 声明一个共享整型数组,具有 THREADS 个元素,因为我们假定四个线程来运行该程序, 所以 THREADS 的值为 4。这个数组用来记录各个线程所算出来的元素和。 */ upc_lock_t *lock; // 声明一个类型为 upc_lock_t 的指针 int main() { lock=upc_all_lock_alloc(); // 给每一个线程分配一个共同的锁,并将其地址分配给 lock 指针 upc_forall(int i=0;i<N;i++;&A[i]) //upc_forall 语句根据亲缘关系表达式给线程分工 { A[i]=i; // 将数组 A 的元素初始化 } upc_barrier; // 阻挡障碍确保每个线程都完成对数组 A 的元素初始化 if(lock != NULL) // 如果成功地分配了这个锁 { upc_forall(int i=0;i<N;i++;&A[i]) // 各个线程计算自己本地分配的数组元素的和 { partialsum[MYTHREAD] +=A[i]; } upc_barrier; // 阻挡障碍确保每个线程完成计算,再向前执行。 upc_lock(lock); /* 这里到了程序的关键部分,因为 sum 是一个共享数据,可以被所有线程同时操作, 所以这里加个锁,只允许同一个时间内一个线程来操作 sum 变量,从而避免了竞争状态, 保证了程序的正确性 */ sum +=partialsum[MYTHREAD]; // 将所有线程的分别计算出来的和加起来就是数组 A 所有元素的和 upc_unlock(lock); // 开锁 upc_barrier; // 阻挡障碍确保每个线程计算出来的和都加到 sum 上,再向前执行 if(MYTHREAD == 0) // 如果执行该语句的是线程 0 的话,则输出计算结果 { upc_lock_free(lock); // 释放分配的锁 printf("Th:%d, result=%d \n",MYTHREAD,sum); return 1; } } return 0; }