LoginSignup
17
19

More than 5 years have passed since last update.

C++11でバリア同期

Last updated at Posted at 2016-01-19

動機

C++11でカジュアルにスレッドが作れるようになったのに、そのバリア同期手段はboost::barrierかpthread_barrierぐらいしか使えなくてもっと依存のないポータブルな実装が欲しい事があったので書き捨てたものを公開。
condition_variablenotify_allを使った物が一般的だけれど、短時間で同期できることがわかっている場合にはスピンによる待機が一番パフォーマンスが出るのでスピンにした。

実装

The Art of Multiprocessor Programmingのセンス反転バリアをそのまま実装した。
スレッドローカルストレージをクラスごとにポータブルに作る方法が分からなかったし、そもそもスレッドは開始時にTIDを渡しているのでそれをwait()の引数に渡すようにした。
やりたい事はbooleanの反転だったけれどstd::vector<bool>は触ってはいけない(特にマルチスレッド環境にはあまり良くないテンプレート特殊化がされている)のでstd::vector<int>を利用した。
随所で <<6 とビットシフトしているのは、個々のスレッドの状態を保持する場所同士がキャッシュラインの都合上64byteずつ離れていて欲しかったから。

#include <atomic>
#include <vector>

class spin_barrier {
  spin_barrier() = delete;
  spin_barrier(const spin_barrier &) = delete;
  spin_barrier& operator=(const spin_barrier &) = delete;
public:
  spin_barrier(size_t threads) :
      threads_(static_cast<int>(threads)),
      waits_(static_cast<int>(threads)),
      sense_(false),
      my_sense_(threads << 6) {
    for (size_t i = 0; i < threads; ++i) {
      my_sense_[i << 6] = true;
    }
  }

  void wait(int i) {
    int sense = my_sense_[i << 6];
    if (waits_.fetch_sub(1) == 1) {
      waits_.store(threads_);
      sense_.store(sense != 0, std::memory_order_release);
    } else {
      while (sense != sense_);
    }
    my_sense_[i << 6] = !sense;
  }
private:
  const int threads_;
  std::atomic<int> waits_;
  std::atomic<bool> sense_;
  std::vector<int> my_sense_;
};

使い方

10スレッドが100回バリア同期するだけのコード。
コンパイル時には -std=c++11-pthread オプションを忘れずに。

#include <iostream>
#include <thread>
#include <vector>

// ここに上のbarrierクラスを書く

int main() {
  const int n_workers = 10;
  spin_barrier barrier(n_workers);  // shared
  std::vector<std::thread> workers;

  workers.reserve(n_workers);
  for (int tid = 0; tid < n_workers; ++tid) {
    workers.emplace_back([&, tid] {
      for (int i = 0; i < 100; ++i) {
        barrier.wait(tid);
        std::cerr << "[" << tid << "]: "
            << i << "th barrier ok." << std::endl;
      }
    });
  }
  for (auto& worker : workers) {
    worker.join();
  }
}

簡単ですね。

17
19
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
19