SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

インテルTBBの同期メカニズム

mutex ひとめぐり


公平なmutex

 最後にmutexのバリエーションをもうひとつ。

 int valueを1つ用意し、複数のスレッドがひっきりなしに++valueします。もちろんデータレースを起こさないようmutexでガードをかけて。この処理を1秒間繰り返し、各スレッドが何回++valueできたかを勘定します。各スレッドの++valueした回数を、平均値を100として正規化しました。

#include <tbb/tbb.h>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <numeric>
#include <array>

using namespace std;

void run() {
  const int N = 10;
  tbb::spin_mutex mtx;
  int value; // コレに対しN個のスレッドがアクセスする
  array<int,N> count;
  fill(count.begin(), count.end(), 0);
  tbb::spin_rw_mutex start;
  start.lock();

  array<tbb::tbb_thread,N> threads;
  tbb::tick_count cnt = tbb::tick_count::now();
  for ( int i = 0; i < N; ++i ) {
    threads[i] = tbb::tbb_thread([&](int n) {
      tbb::spin_rw_mutex::scoped_lock lock(start,false); // スタートを待つ
      int c = 0;
      // 1秒間、共有変数valueにアクセスし
      while ( (tbb::tick_count::now() - cnt).seconds() < 1.0 ) {
        tbb::spin_mutex::scoped_lock lock(mtx);
        ++value;
        ++c;
      }
      count[n] = c; // その回数を記録する
    },i);
  }
  start.unlock(); // 全員同時にスタート
  // 全員の終了を待つ
  for_each(threads.begin(), threads.end(),
           [](tbb::tbb_thread& thr) { thr.join();});
  // アクセス回数を、その平均を100に正規化して出力
  double mean = accumulate(count.begin(), count.end(), 0.0) / count.size();
  for_each(count.begin(), count.end(), [&](int c) { cout << setw(4) <<
static_cast<int>(c/mean*100.0);});
  cout << "  mean= " << mean << endl;
}

int main() {
  for ( int i = 0; i < 10; ++i ) {
    run();
  }
}

 スレッドの仕事量にバラツキがあります。複数のスレッドが実行権をaquireするとき、どのスレッドが獲得するかは、いわば「運次第」です。イス取りゲームやってるようなもので、運が悪いスレッドはちっとも実行権がもらえずに長い間待たされることもあります。フェア(公平)じゃないんですね。

 この不公平を解消するのがqueuing_mutexです。実行権を手に入れるためacquireを開始した順に行儀よく列を作って待ちます。全体のパフォーマンスは落ちますが、実行権はそれぞれのスレッドに「ほぼ」公平に分配されます。

 上記コードのtbb::spin_mutexをtbb::queuing_mutexに差し替えると、

 平均アクセス数が減ってはいますが、バラツキがかなり軽減されているのが見て取れます。

 並列プログラミングは正直面倒です。思いもしない現象でプログラマを泣かせてくれます。しかしながら消費電力(つまり発熱)の問題からCPUのクロック数の上昇は頭打ちであり、単一スレッドでの速度向上は見込めないのが現状で、CPUのコアを増やし並列プログラミングでパフォーマンスを稼ごうとしています。つまりはプログラマの腕次第ということです。プログラマには悩ましくも胸躍る時代になりそうです。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
特集記事連載記事一覧

もっと読む

この記事の著者

επιστημη(エピステーメー)

C++に首まで浸かったプログラマ。Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"りわんくま同盟でたまにセッションスピーカやったり中国茶淹れてにわか茶...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/6090 2011/09/01 10:48

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー