1

マルチスレッドアプリを書いています。

boost::interprocess クラスを使用していました (バージョン 1.36.0)

基本的に、私は作業が可能になったときに通知する必要があるワーカー スレッドを持っています。

「セマフォ」と「条件」の両方のアプローチを試しました。

どちらの場合も、ワーカー スレッドの CSwitch (コンテキスト スイッチ) は、1 秒あたり 600 回の切り替えなど、非常に高いように見えました。

私はコードを見て、(アトミックにミューテックスを使用して) フラグをチェックし、次に再試行する前にタイムスライスを生成するようです。

コードで WaitForSingleObject などを使用することを期待していました。

皮肉なことに、これはまさに私が「適切に」実行して Boost を使用することを決定する前に行っていた方法でした! (つまり、mutex を使用してフラグの状態を定期的にチェックします)。唯一の違いは、私のアプローチでは、チェックの間に 50 ミリ秒ほど寝ていたので、高い CSwitch の問題はありませんでした (そして、50 ミリ秒まで作業が開始されないことは問題ありません)。

いくつかの質問:

  1. この「高い」CSwitch 値は重要ですか?
  2. ブースト ライブラリがセマフォの代わりに CRITICAL_SECTIONS を使用していた場合、これは発生しますか (プロセス間の同期は気にしません - すべてのスレッドが同じプロセスにあります)。
  3. ブーストが WaitForSingleObject を使用していた場合、これは発生しますか?
  4. Boost ライブラリには、前述の Win32 待機メソッド (WaitForXXX) を使用する別のアプローチがありますが、これはこの CSwitch の問題に悩まされることはないと思います。

更新:これは疑似コード サンプルです。少し複雑になるため、実際のコードを追加することはできません。しかし、これは私がやっていることのほとんどです。これは、1 回限りの非同期アクティビティを実行するスレッドを開始するだけです。

注:これらは単なるイラストです。このサンプルには負荷がありません。たとえば、スレッドが「待機」に達する前に injectWork() を呼び出した場合、機能しません。ブーストの使い方を説明したかっただけです。

使用法は次のようなものです。

int main(int argc, char** args)
{
  MyWorkerThread thread;
  thread.startThread();

  ...

  thread.injectWork("hello world");
}

これはブーストを使用した例です。

class MyWorkerThread
{
public:

  /// Do work asynchronously
  void injectWork(string blah)
  {
    this->blah = blah;

    // Notify semaphore
    this->semaphore->post();
  }

  void startThread()
  {
    // Start the thread (Pseudo code)
    CreateThread(threadHelper, this, ...);
  }

private: 


  static void threadHelper(void* param)
  {
    ((MyWorkerThread*)param)->thread();
  }

  /// The thread method
  void thread()
  {
    // Wait for semaphore to be invoked
    semaphore->wait();

    cout << blah << endl;
  }

  string blah;  
  boost::interprocess::interprocess_semaphore* semaphore;
};

そして、これが私の「素朴な」ポーリングコードです。

class MyWorkerThread_NaivePolling
{
public:

  MyWorkerThread_NaivePolling()
  {
    workReady = false;
  }

  /// Do work asynchronously
  void injectWork(string blah)
  {
    section.lock();

    this->blah = blah;
    this->workReady = true;

    section.unlock();
  }

  void startThread()
  {
    // Start the thread (Pseudo code)
    CreateThread(threadHelper, this, ...);
  }

private: 

  /// Uses Win32 CriticalSection
  class MyCriticalSection
  {
    MyCriticalSection();
    void lock();
    void unlock();
  };

  MyCriticalSection section;


  static void threadHelper(void* param)
  {
    ((MyWorkerThread*)param)->thread();
  }

  /// The thread method
  void thread()
  {
    while (true)
    {
      bool myWorkReady = false;
      string myBlah;

      // See if work set 
      section.lock();
      if (this->workReady)
      {
        myWorkReady = true;
        myBlah = this->blah;
      }
      section.unlock();

      if (myWorkReady)
      {
        cout << blah << endl;
        return;
      }
      else
      {
        // No work so sleep for a while
        Sleep(50);
      }
    }
  }

  string blah;  
  bool workReady;
};

乾杯、

ジョン

4

2 に答える 2

3

非POSIXシステムでinterprocess_conditionは、質問で説明しているように、ループを使用してエミュレートされているようです。Andinterprocess_semaphoreはミューテックスと でエミュレートされるinterprocess_conditionため、wait() は同じループで終了します。

プロセス間同期は必要ないと述べているため、条件変数の移植可能な実装を提供するBoost.Threadを確認する必要があります。面白いことに、これは Windows では "従来の" 方法で実装されているようで、... セマフォを使用しています。

于 2009-10-15T19:18:06.647 に答える