9

私はしばらくの間BSPツリーをいじくり回していて、スレッドもいじっています。BSPツリーに三角形を追加すると、データを並列処理する目的で新しいスレッドを作成する機会が生じます。

insert(triangle、bspnode)
{{
  ...。
  else if(三角形はbspnodeにまたがる)
  {{
    (口絵、口絵)= plain_split(triangle、bspnode)

    挿入(口絵、bspnode.front)
    insert(backpiece、bspnode.back)
  }
  ...。
}

上記の2つの挿入操作は、2つのスレッドで実行できます。また、同じデータを変更しないため、安価な同期を使用できます。

insert(triangle、bspnode)
{{
  ...。
  else if(三角形はbspnodeにまたがる)
  {{
    (口絵、口絵)= split(triangle、bspnode)

    handle = beginthread(insert(backpiece、bspnode.front))
    挿入(口絵、bspnode.back)
    if(ハンドル)
    {{
      waitforthread(ハンドル)
    }
    そうしないと
    {{
      insert(backpiece、bspnode.front)
    }
  }
  ...。
}

この新しいメソッドは、スレッドを作成して操作を並行して完了しようとしますが、スレッドを作成できない場合でも失敗することはありません(単に元のアルゴリズムに戻ります)。

これは適切なプログラミング手法ですか、それともスレッドを不適切に使用していますか?私はこの技術に関する文献を見つけることができませんでした。私は、CPUを最大限に(2コア)使用する傾向があり、理論的には、使用可能な任意の数のプロセッサーに拡張できるのが好きです。CPUとメモリにひどく無駄になるのは好きではありません。

4

3 に答える 3

13

スレッドは、処理の一部が外部の何か(ユーザー入力、I / O、その他の処理)を待機している場合に最適です。待機しているスレッドは待機を継続できますが、待機していないスレッドは先に進みます。

ただし、処理集約型のタスクの場合、プロセッサよりも多くのスレッドが実際にオーバーヘッドを作成します。あなたのスレッドはすべての「CPU作業」を行っているように見えるので、コアごとに1つのスレッドに固執します。ただし、最適な数を見つけるためにテストしてください。

作成される最大のオーバーヘッドは、コンテキストの切り替え(1つのスレッドをフリーズして次のスレッドの実行コンテキストをロードする)と、スレッドが異なるメモリでタスクを実行しているときのキャッシュミス(スレッドがCPUキャッシュを効果的に使用できる場合)によるものです。

于 2008-10-03T14:03:01.450 に答える
2

最善の策は、スレッドプールを作成し、それを「透過的に」使用してノードを追加することです。

たとえば、プログラムの開始時に2つのスレッドを作成し、セマフォまたはイベントを待機させます。追加するノードがある場合は、データをキューにポップしてから、セマフォをトリガーします。これにより、データをキューからポップして処理を実行するスレッドの1つがウェイクアップされます。(キューへのアクセスがスレッドセーフであることを確認してください。クリティカルセクションと完全に同期するのが最適です)。

データをキューにコピーして追加のスレッドを実行する際のオーバーヘッドが増えるため、アプリの全体的なパフォーマンスは低下しますが、以前はシングルコアで実行していた場合は、2で実行することになります。スレッド化されている場合に最適に機能します。処理には費用がかかります。

于 2008-10-03T14:29:32.910 に答える
0

確かに、たとえば、クイックソートはマルチスレッドで非常に簡単にプログラムでき、マルチコアシステムではパフォーマンスが大幅に向上し、マルチスレッドではない場合はパフォーマンスがわずかに低下します。ここでオーバーヘッドを2回追加していることを覚えておいてください。1回は再帰のスタック保存用で、もう1回はスレッドでの保存です。したがって、多数の再帰を実行している場合、非マルチスレッドアプローチよりも速くシステムを圧倒する可能性があります。

于 2008-10-03T14:36:00.150 に答える