用pthreads并行实现高斯消除

时间:2015-07-29 09:59:39

标签: c multithreading algorithm pthreads gaussian

我需要使用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,但没有得到关于如何为它的并行版本构造逻辑的单一提示(线程工作分配标准,循环到并行化等)。任何线索或起点都会帮助我继续。

1 个答案:

答案 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上的循环,以获取从j0的{​​{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);