0

(どこで何か間違っているのかを見つけるために、これをできるだけ単純化しようとしました。)

コードのアイデアは、グローバル配列 *v を持っていることです (この配列を使用しても速度が低下しないことを願っています。スレッドはすべて異なる範囲で動作するため、スレッドが同じ値にアクセスすることはありません)。2 つのスレッドを作成しようとしています。それぞれが、それぞれのパラメーターを指定して関数 merge_sort() を呼び出して、前半と後半をそれぞれソートします。

スレッド化された実行では、プロセスが 80 ~ 100% の CPU 使用率 (デュアル コア CPU の場合) に達していることがわかりますが、非スレッド実行では 50% のままですが、実行時間は非常に近いです。


これは(関連する)コードです:

//これらは 2 つのソート関数で、各スレッドは merge_sort(..) を呼び出します。これは問題ですか?両方のスレッドが同じ (通常の) 関数を呼び出していますか?

void merge (int *v, int start, int middle, int end) {
    //dynamically creates 2 new arrays for the v[start..middle] and v[middle+1..end]
    //copies the original values into the 2 halves
    //then sorts them back into the v array
}

void merge_sort (int *v, int start, int end) {
    //recursively calls merge_sort(start, (start+end)/2) and merge_sort((start+end)/2+1, end) to sort them
    //calls merge(start, middle, end) 
}

//ここでは、各スレッドが作成され、その特定の範囲で merge_sort が呼び出されることを期待しています (これは、バグを見つけやすくするために元のコードを簡略化したものです)

void* mergesort_t2(void * arg) {
    t_data* th_info = (t_data*)arg;
    merge_sort(v, th_info->a, th_info->b);
    return (void*)0;
}

//メインでは、上記の関数を呼び出す 2 つのスレッドを作成するだけです

int main (int argc, char* argv[])
{
    //some stuff

    //getting the clock to calculate run time
    clock_t t_inceput, t_sfarsit;
    t_inceput = clock();

    //ignore crt_depth for this example (in the full code i'm recursively creating new threads and i need this to know when to stop)
    //the a and b are the range of values the created thread will have to sort
    pthread_t thread[2];
    t_data next_info[2];
    next_info[0].crt_depth = 1;
    next_info[0].a = 0;
    next_info[0].b = n/2;
    next_info[1].crt_depth = 1;
    next_info[1].a = n/2+1;
    next_info[1].b = n-1;

    for (int i=0; i<2; i++) {
        if (pthread_create (&thread[i], NULL, &mergesort_t2, &next_info[i]) != 0) {
            cerr<<"error\n;";
            return err;
        }
    }

    for (int i=0; i<2; i++) {
        if (pthread_join(thread[i], &status) != 0) {
            cerr<<"error\n;";
            return err;
        }
    }

    //now i merge the 2 sorted halves
    merge(v, 0, n/2, n-1);

    //calculate end time
    t_sfarsit = clock();

    cout<<"Sort time (s): "<<double(t_sfarsit - t_inceput)/CLOCKS_PER_SEC<<endl;
    delete [] v;
}

出力 (100 万の値):

Sort time (s): 1.294

スレッドなしで、merge_sort を直接呼び出して出力します。

Sort time (s): 1.388

出力 (1000 万の値):

Sort time (s): 12.75

スレッドなしで、merge_sort を直接呼び出して出力します。

Sort time (s): 13.838

解決:

WhozCraig と Adam にも感謝したいと思います。彼らは最初からこれを示唆していました。

私はinplace_merge(..)自分の代わりに関数を使用しましたが、プログラムの実行時間は現在のようになっています。

これが私の最初のマージ関数です(最初のものかどうかはよくわかりません。おそらく数回変更したため、配列インデックスも今間違っている可能性があります。[a、b]と[a、bの間を行ったり来たりしました) 、これは最後のコメントアウトされたバージョンです):

void merge (int *v, int a, int m, int c) { //sorts v[a,m] - v[m+1,c] in v[a,c]

    //create the 2 new arrays
    int *st = new int[m-a+1];
    int *dr = new int[c-m+1];
    //copy the values
    for (int i1 = 0; i1 <= m-a; i1++)
        st[i1] = v[a+i1];
    for (int i2 = 0; i2 <= c-(m+1); i2++)
        dr[i2] = v[m+1+i2];

    //merge them back together in sorted order
    int is=0, id=0;
    for (int i=0; i<=c-a; i++)  {
        if (id+m+1 > c || (a+is <= m && st[is] <= dr[id])) {
            v[a+i] = st[is];
            is++;
        }
        else {
            v[a+i] = dr[id];
            id++;
        }
    }
    delete st, dr;
}

これはすべて次のものに置き換えられました。

inplace_merge(v+a, v+m, v+c);

編集、私の3GHzデュアルコアCPUで時々:

100 万の値: 1 スレッド: 7.236 秒 2 スレッド: 4.622 秒 4 スレッド: 4.692 秒

1000 万の値: 1 スレッド: 82.034 秒 2 スレッド: 46.189 秒 4 スレッド: 47.36 秒

4

2 に答える 2