我需要使用pthreads实现以下Gauss消除算法的并行版本。
procedure GAUSSIAN ELIMINATION (A, b, y)
begin
for k := 0 to n − 1 do /* Outer loop */
begin
for j := k + 1 to n − 1 do
A[k, j] := A[k, j]/A[k, k]; /* Division step */
y[k] := b[k]/A[k, k];
A[k, k] := 1;
for i := k + 1 to n − 1 do
begin
for j := k + 1 to n − 1 do
A[i, j] := A[i, j] − A[i, k] × A[k, j]; /* Elimination step */
b[i] := b[i] − A[i, k] × y[k];
A[i, k] := 0;
endfor; /* Line 9 */
endfor; /* Line 3 */
end GAUSSIAN ELIMINATION
我理解顺序实现和pthreads,但没有得到关于如何为它的并行版本构造逻辑的单一提示(线程工作分配标准,循环到并行化等)。任何线索或起点都会帮助我继续。
答案 0 :(得分:3)
矩阵中每一行的工作需要完成之前的所有行,因此您无法按此方式划分工作。
但是,在一行中,每个列都可以并行处理(需要注意的是,k
- 列的原始值必须保存并用于计算其他列。这与您的j
值相对应。
我相信您可以重新排列算法以使其更容易,因此j
只有一个循环:
procedure GAUSSIAN ELIMINATION (A, b, y)
begin
for k := 0 to n − 1 do /* Outer loop */
begin
for j := k + 1 to n − 1 do
begin
A[k, j] := A[k, j]/A[k, k]; /* Division step */
for i := k + 1 to n − 1 do
A[i, j] := A[i, j] − A[i, k] × A[k, j]; /* Elimination step */
endfor;
y[k] := b[k]/A[k, k];
A[k, k] := 1;
for i := k + 1 to n − 1 do
begin
b[i] := b[i] − A[i, k] × y[k];
A[i, k] := 0;
endfor;
endfor;
end GAUSSIAN ELIMINATION
请注意,j
上的循环体仅访问j
列和k
列中的值 - 这是可以并行完成的循环。然后你可以进一步注意到外环的第二部分不依赖于第一部分,所以你可以将外环分成两部分:
procedure GAUSSIAN ELIMINATION (A, b, y)
begin
for k := 0 to n − 1 do /* Outer loop */
begin
for j := k + 1 to n − 1 do
begin
A[k, j] := A[k, j]/A[k, k]; /* Division step */
for i := k + 1 to n − 1 do
A[i, j] := A[i, j] − A[i, k] × A[k, j]; /* Elimination step */
endfor;
endfor;
for k := 0 to n − 1 do /* Outer loop, second pass */
begin
y[k] := b[k]/A[k, k];
A[k, k] := 1;
for i := k + 1 to n − 1 do
begin
b[i] := b[i] − A[i, k] × y[k];
A[i, k] := 0;
endfor;
endfor;
end GAUSSIAN ELIMINATION
您可以预先创建线程,每个线程负责执行j
上的循环,以获取从j
到0
的{{1}}值的子集。处理完每一行后,这些线程将需要一个同步障碍,因为前一行的所有列的结果都需要处理下一行。您可以使用n - 1
。
您会注意到并非每一列(pthread_barrier_wait()
的值)都具有相同的功能。列j
由该循环j
次处理(因此列0执行0次,列j
执行n - 1
次)。您需要为线程分配列号,以便每个线程尽可能接近相同的工作量 - 这可以通过以循环方式分配列来完成。例如。如果你有三个线程A,B和C以及从0到9的10个列,你可以分配它们:
n - 1
线程函数看起来像:
Thread A: 0, 3, 6, 9
Thread B: 1, 4, 7,
Thread C: 2, 5, 8,
主要功能如下:
for k := 0 to n − 1 do /* Outer loop */
begin
call pthread_barrier_wait(row_barrier);
for j := k + 1 + thread_number to n − 1 step n_threads do
begin
A[k, j] := A[k, j]/A[k, k]; /* Division step */
for i := k + 1 to n − 1 do
A[i, j] := A[i, j] − A[i, k] × A[k, j]; /* Elimination step */
endfor;
endfor;
call pthread_barrier_wait(phase1_barrier);