7

10ミリ秒ごとに何かをする必要があるスレッドがあります。だから私はそのような非常に単純なコードを持っています:

while (work) {
    // do something
    Sleep(10000); // boost sleep can be also used
}

一般的には推奨されていないと聞きました。Sleepこれを代用すると、deadline_timerアプリケーション全体のパフォーマンスが向上します。特に、コストのかかる「コンテキスト スイッチ」を回避できます。

変更sleepする必要deadline_timerがありますか?もしそうなら、誰かが例を挙げてもらえますか?

4

2 に答える 2

19

それはすべて、10ms の要件に依存します。


反復間の 10 ミリ秒の遅延

アプリケーションが反復間に 10 ミリ秒の遅延を必要とする場合は、スリープで問題ありません。work()完了するまでに 7 ミリ秒かかると仮定すると、タイムラインは次のようになります。

時間 | アクション
-------+------------
0.000 秒 | 仕事を始める
0.007秒 | 仕事を終える、ブロックする
0.017秒 | ブロッキングを終了し、作業を開始します
0.024秒 | 仕事を終える、ブロックする
0.034 秒 | ブロッキングを終了し、作業を開始します

this_thread::sleep_for()読みやすさのためにBoost.Thread の使用を検討する価値があるかもしれません。

#include <boost/thread.hpp>

int main()
{
  for (;;)
  {
    work();
    boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
  }
}

反復間の最大遅延は 10 ミリ秒

反復間の最大遅延が 10 ミリ秒の場合、作業の実行に費やす時間を 10 ミリ秒の遅延から減らす必要があります。work()完了するまでに 7 ミリ秒かかると仮定すると、タイムラインは次のようになります。

時間 | アクション
-------+------------
0.000 秒 | 仕事を始める
0.007秒 | 仕事を終える、ブロックする
0.010 秒 | ブロッキングを終了し、作業を開始します
0.017秒 | 仕事を終える、ブロックする
0.020 秒 | ブロッキングを終了し、作業を開始します

タイマーを同期的に使用するチュートリアルは、開始するのに適した場所です。考慮すべき点の 1 つは、Boost.Asio がいくつかのタイマーを提供することです。10 ミリ秒の遅延がシステム クロックの変更による影響を受けない場合は、 の使用を検討してsteady_timerください。そうでdeadline_timerなければ、問題ないはずです。

#include <boost/asio/steady_timer.hpp>

boost::asio::io_service io_service;
boost::asio::steady_timer timer(io_service);

int main()
{
  for (;;)
  {
    timer.expires_from_now(boost::chrono::milliseconds(10));
    work();
    timer.wait();
  }
}

もう 1 つの考慮事項は、work()完了までに 13 ミリ秒かかる場合、最大遅延を超えているため、作業間に遅延がないことです。ただし、これは10 ミリ秒ごとwork()ではなく、13 ミリ秒ごとに実行されることになりwork()ます。

時間 | アクション
-------+------------
0.000 秒 | 仕事を始める
0.013 秒 | 仕事を終える、ブロックする
0.013 秒 | ブロッキングを終了し、作業を開始します
0.026秒 | 仕事を終える、ブロックする
0.039 秒 | ブロッキングを終了し、作業を開始します

10msごとに作業を行う

完了するのにかかる時間がwork()遅延を超える場合、 work()10ms ごとに実行されません。これを実現するには、複数のスレッドを使用する必要がある場合があります。以下は、10 ミリ秒ごとにスケジュールされた作業を非同期に実行する 2 つのスレッドのタイムラインですが、完了するまでに 13 ミリ秒かかります。

時間 | スレッド A | スレッド B
-------+----------------------------+------------- --------------
0.000 秒 | 仕事をスケジュールする、仕事を始める |
0.010 秒 | | | 仕事をスケジュールする、仕事を始める
0.013 秒 | 仕事を終えて、ブロック |
0.020 秒 | 仕事をスケジュールする、仕事を始める |
0.023 秒 | | | 仕事を終える、ブロックする
0.030 秒 | | | 仕事をスケジュールする、仕事を始める
0.033 秒 | 仕事を終えて、ブロック |

タイマーを非同期的に使用することで、基本的な導入が提供される場合があります。全体的な考え方は、 に作業を追加することio_serviceであり、 を実行しているスレッドが 10 ミリ秒ごとio_serviceに選択されて が呼び出されwork()ます。スレッド プールのサイズは、完了までの時間に基づいて増減できますwork()。作業に 7 ミリ秒かかる場合、単一のスレッドがタイマーで非同期に待機できます。

#include <boost/asio/steady_timer.hpp>

boost::asio::io_service io_service;
boost::asio::steady_timer timer(io_service);

void handle_timer(const boost::system::error_code& error);

void schedule_work()
{
  // Schedule more work.
  timer.expires_from_now(boost::chrono::milliseconds(10));
  timer.async_wait(&handle_timer);
}

void handle_timer(const boost::system::error_code& error)
{
  if (error) return;
  schedule_work();
  work();
}

int main()
{
  // Add work to io_service.
  schedule_work();

  // Create 2 threads that will run io_service.
  boost::thread_group threads;
  for (std::size_t i = 0; i < 2; ++i)
    threads.create_thread(boost::bind(
      &boost::asio::io_service::run, &io_service));

  // Wait for threads to finish.
  threads.join_all();
}

締め切りに間に合わせるために並行性を導入する場合は、それwork()がスレッドセーフであることを確認してください。

于 2013-05-03T16:52:16.943 に答える
1

使用Sleep()OKです。とにかくミリ秒かかるWindows API関数だと思いますので、10ミリ秒が必要な場合は、おそらく10000ではなく10を渡す必要があります。

このようなスリープを使用する単純なプログラムの最大の問題は、ドリフトかもしれません。間隔を非常に正確にする必要がある場合は、いくつかの課題に直面します。実際のロジックが完了するのに数ミリ秒かかる場合に何が起こるかを気にするかどうかは言いませんでした.10ミリ秒後に次の反復を開始するか、「追いつく」ためにそれ以下にすることができます。

于 2013-05-03T10:19:52.387 に答える