4

WaitForSingleObject()およびWaitForMultipleObjects()と同じセマンティクスを持つ関数を介してチェックできるWin32リセットイベントを彷彿とさせるメカニズムが必要です(現時点では..SingleObject()バージョンのみが必要です)。しかし、私は複数のプラットフォームをターゲットにしているので、私が持っているのはboost :: threads(AFAIK)だけです。私は次のクラスを思いついたので、潜在的な問題について、そしてそれがタスクに任されているかどうかについて質問したいと思いました。前もって感謝します。

class reset_event
{
 bool flag, auto_reset;
 boost::condition_variable cond_var;
 boost::mutex mx_flag;

public:
 reset_event(bool _auto_reset = false) : flag(false), auto_reset(_auto_reset)
 {
 }

 void wait()
 {
  boost::unique_lock<boost::mutex> LOCK(mx_flag);
  if (flag)
   return;

  cond_var.wait(LOCK);
  if (auto_reset)
   flag = false;
 }

 bool wait(const boost::posix_time::time_duration& dur)
 {
  boost::unique_lock<boost::mutex> LOCK(mx_flag);
  bool ret = cond_var.timed_wait(LOCK, dur) || flag;
  if (auto_reset && ret)
   flag = false;

  return ret;
 }

 void set()
 {
  boost::lock_guard<boost::mutex> LOCK(mx_flag);
  flag = true;
  cond_var.notify_all();
 }

 void reset()
 {
  boost::lock_guard<boost::mutex> LOCK(mx_flag);
  flag = false;
 }
};

使用例;

reset_event terminate_thread;

void fn_thread()
{
 while(!terminate_thread.wait(boost::posix_time::milliseconds(10)))
 {
  std::cout << "working..." << std::endl;
  boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
 }

 std::cout << "thread terminated" << std::endl;
}

int main()
{
 boost::thread worker(fn_thread);

 boost::this_thread::sleep(boost::posix_time::seconds(1));
 terminate_thread.set();

 worker.join();

 return 0;
}

編集

MichaelBurrの提案に従ってコードを修正しました。私の「非常に単純な」テストは問題がないことを示しています。

class reset_event
{
    bool flag, auto_reset;
    boost::condition_variable cond_var;
    boost::mutex mx_flag;

public:
    explicit reset_event(bool _auto_reset = false) : flag(false), auto_reset(_auto_reset)
    {
    }

    void wait()
    {
        boost::unique_lock<boost::mutex> LOCK(mx_flag);
        if (flag)
        {
            if (auto_reset)
                flag = false;
            return;
        }

        do
        {
            cond_var.wait(LOCK);
        } while(!flag);

        if (auto_reset)
            flag = false;
    }

    bool wait(const boost::posix_time::time_duration& dur)
    {
        boost::unique_lock<boost::mutex> LOCK(mx_flag);
        if (flag)
        {
            if (auto_reset)
                flag = false;
            return true;
        }

        bool ret = cond_var.timed_wait(LOCK, dur);
        if (ret && flag)
        {
            if (auto_reset)
                flag = false;

            return true;
        }

        return false;
    }

    void set()
    {
        boost::lock_guard<boost::mutex> LOCK(mx_flag);
        flag = true;
        cond_var.notify_all();
    }

    void reset()
    {
        boost::lock_guard<boost::mutex> LOCK(mx_flag);
        flag = false;
    }
};
4

2 に答える 2

3

チェック/修正が必要ないくつかの点 (注 - これらが唯一のものだと言っているわけではありません - 私はざっと見ただけです):

  • 関数ではwait()、次のように設定されている場合、既に通知されたイベントでリセットしませんauto_reset

     void wait()
     {
      boost::unique_lock<boost::mutex> LOCK(mx_flag);
      if (flag) {
       if (auto_reset) flag = false;    // <-- I think you need this
       return;
      }
    
      cond_var.wait(LOCK);
      if (auto_reset)
       flag = false;
     }
    
  • 条件変数を待つ 前に確認するwait(const boost::posix_time::time_duration& dur)必要があります。flag

  • どちらのwait関数でも、条件変数を待機する場合は、その間に他のスレッドがイベントをリセットしていないことを確認するために、フラグを再チェックする必要がある場合があります。これは、複数のスレッドがイベントで待機している場合でも、単一のウェイターのみを解放する必要がある auto_reset イベントに特に当てはまります。

于 2011-01-14T16:11:38.947 に答える
1

これは、次のことを実現するために少し調整された私のバージョンです。

  • set()、reset()などを使用してプロデューサーをブロックすることはありません。代わりに、ブール条件が真になった後に1:1マッピングを失うのではなく、「リリース」の数をカウントします。
  • 外部の呼び出し元がwait()のミューテックスを指定できるようにします。これは、私の使用シナリオではとにかく外部のリソースであることが多く、内部のミューテックスから分離することができます。
  • set()、reset_one()、reset_all()呼び出しを内部ミューテックスに移動しました。コンシューマーがwait()を呼び出す前に繰り返し呼び出されても、ブロックされなくなりました。

これで、読み込み中のスレッドは、処理中のタスクをドロップすることなく、複数の長期間有効なリクエストをキューに入れることができます。

私のプロジェクトの進捗状況を使用して...

ブースト条件変数: -> 3つのロード要求を送信します。スレッドはビジーで、1つまたは2つしか表示されません
。Boolを使用して投稿された回答: -> 3つのロード要求を送信し、共有ミューテックスのために2番目の要求でプロデューサーブロック。プロデューサーは、最初のロード要求が処理されるまでブロックを解除しません。
私のバージョン->3つのロード要求を送信すると、プロデューサーは3つすべてからすぐに戻り、コンシューマーは3つのロード要求をゆっくりとしかし確実に確認します:)

うまくいけば、それはそこに誰かを助けます。

    クラスcNonLossyCondition
    {{
        ブールフラグ、auto_reset;
        boost :: condition_variable cond_var;
        int lost_signals;
        boost :: mutex internal_mutex;

    公衆:
        cNonLossyCondition(bool _auto_reset)
        {{
            this-> flag = false;
            this-> auto_reset = auto_reset;
            this-> lost_signals = 0;
        }

        void wait(boost :: mutex * mx_flag)
        {{
            boost :: unique_lock LOCK(* mx_flag);
            if(フラグ)
            {{
                if(auto_reset)
                    this-> reset_one();
                戻る;
            }

            行う
            {{
                cond_var.wait(LOCK);
            } while(!flag);

            if(auto_reset)
                this-> reset_one();
        }

        bool wait(boost :: mutex * mx_flag、const boost :: posix_time :: time_duration&dur)
        {{
            boost :: unique_lock LOCK(* mx_flag);
            if(フラグ)
            {{
                if(auto_reset)
                    this-> reset_one();
                trueを返します。
            }

            bool ret = cond_var.timed_wait(LOCK、dur);
            if(ret &&フラグ)
            {{
                if(auto_reset)
                    this-> reset_one();

                trueを返します。
            }

            falseを返します。
        }

        void set()
        {{
            boost :: lock_guard LOCK(this-> internal_mutex);
            フラグ=true;
            if(this-> lost_signals lost_signals =1;//すでにインクリメントされています
            } そうしないと {
                this-> lost_signals = this-> lost_signals + 1;
            }

            cond_var.notify_all();
        }

        void reset_one()
        {{
            boost :: lock_guard LOCK(this-> internal_mutex);
            this-> lost_signals = this-> lost_signals-1;
            if(this-> lost_signals lost_signals = 0;
                フラグ=false;
            }

        }
        void reset_all()
        {{
            boost :: lock_guard LOCK(this-> internal_mutex);
            フラグ=false;
            this-> lost_signals = 0;
        }
    };

于 2012-08-30T03:01:48.190 に答える