Каков наилучший способ выхода из цикла по истечении 30 мс в C ++? - PullRequest
1 голос
/ 03 июня 2009

Каков наилучший способ выхода из цикла как можно ближе к 30 мс в C ++. Повышение опроса: microsec_clock? Опрос QTime? Что-то еще?

Что-то вроде:

A = now;
for (blah; blah; blah) {
    Blah();
    if (now - A > 30000)
         break;
}

Должно работать в Linux, OS X и Windows.

Расчеты в цикле предназначены для обновления симуляции. Каждые 30 мс я хотел бы обновлять область просмотра.

Ответы [ 9 ]

10 голосов
/ 03 июня 2009

Расчеты в цикле для обновление симуляции. Каждые 30 мс я бы нравится обновлять область просмотра.

Рассматривали ли вы использование потоков? То, что вы описываете, кажется идеальным примером того, почему вы должны использовать потоки вместо таймеров.

Поток основного процесса продолжает заботиться об интерфейсе пользователя, и для его обновления QTimer имеет значение 30 мс. Он блокирует QMutex для доступа к данным, выполняет обновление и освобождает мьютекс.

Второй поток (см. QThread ) выполняет симуляцию. Для каждого цикла он блокирует QMutex, выполняет вычисления и освобождает мьютекс, когда данные находятся в стабильном состоянии (подходит для обновления пользовательского интерфейса).

В связи с растущей тенденцией к многоядерным процессорам вы должны больше думать об использовании потоков, чем об использовании таймеров. Ваши приложения автоматически получают выгоду от увеличения мощности (многоядерности) новых процессоров.

4 голосов
/ 03 июня 2009

Хотя это не отвечает на вопрос, это может дать другой взгляд на решение. Как насчет размещения кода симуляции и пользовательского интерфейса в разных потоках? Если вы используете Qt, периодическое обновление может быть реализовано с использованием таймера или даже QThread :: msleep () . Вы можете приспособить резьбовой пример Мандельброта под свои нужды.

2 голосов
/ 04 июня 2009

Вы можете рассмотреть возможность обновления окна просмотра каждые N шагов моделирования, а не каждые K миллисекунд. Если это (скажем) серьезное коммерческое приложение, то вы, вероятно, захотите пойти по многопоточному маршруту, предложенному в другом месте, но если (скажем) это для личного использования или использования с ограниченной аудиторией и что вас действительно интересует это детали того, что вы имитируете, тогда каждый N-шаг прост, переносим и вполне может быть достаточно хорош для продолжения.

2 голосов
/ 03 июня 2009

В соответствии с вашим вопросом каждые 30 мс вы хотите обновить область просмотра. Однажды я написал похожее приложение, которое каждые 500 мс проверяло оборудование на предмет подобных вещей. Хотя это не дает прямого ответа на ваш вопрос, у меня есть следующие наблюдения:

  • Вы уверены, что Blah () для обновления области просмотра может выполняться менее чем за 30 мс в каждом случае?
  • Похоже, что выполнение Blah () будет лучше с помощью обратного вызова по таймеру.
  • Очень трудно найти объект таймера библиотеки, который будет выдвигать интервал 30 мс для обновления в графической структуре. В Windows XP я обнаружил, что стандартный таймер Win32 API, который выдвигает оконные сообщения по истечении интервала таймера, даже на P4 с частотой 2 ГГц, не может выполнять обновления быстрее, чем интервал 300 мс, независимо от того, как низко я установил интервал синхронизации на таймер. Хотя в Win32 API были доступны высокопроизводительные таймеры, они имеют множество ограничений, а именно: вы не можете выполнять какие-либо IPC (например, обновлять виджеты UI) в цикле, подобном тому, который вы цитировали выше.
  • В основном, вы должны очень тщательно спланировать, как вы хотите, чтобы обновления происходили. Возможно, вам придется использовать потоки и посмотреть, как вы хотите обновить область просмотра.

Просто кое-что подумать. Они застали меня врасплох, когда я работал над своим проектом. Если вы уже все продумали, не обращайте внимания на мой ответ: 0).

2 голосов
/ 03 июня 2009

Если вам нужно выполнить работу до истечения определенного времени, то ответ docflabby будет точным. Однако, если вам просто нужно подождать, ничего не делая, пока не истечет указанное время, вам следует использовать usleep()

2 голосов
/ 03 июня 2009

Краткий ответ: вы не можете вообще, но можете, если вы работаете в правильной ОС или на правильном оборудовании.

Вы можете установить значение ЗАКРЫТЬ до 30 мс на всех ОС, используя сборочный вызов для систем Intel и что-то еще на других архитектурах. Я найду ссылку и отредактирую ответ, чтобы включить код, когда найду его.

Проблема заключается в алгоритме среза времени и как близко к концу вашего временного интервала вы находитесь в многозадачной ОС.

В некоторых ОС реального времени в системной библиотеке есть системный вызов, который вы можете сделать, но я не уверен, каким будет этот вызов.

редактировать: LOL! Кто-то уже опубликовал похожий фрагмент на SO: Функция таймера для предоставления времени в нано секундах с использованием C ++

В VonC есть комментарий с кодом сборки таймера ЦП.

2 голосов
/ 03 июня 2009

Пример фрагмента кода в этой ссылке в значительной степени делает то, что вы хотите:

http://www.cplusplus.com/reference/clibrary/ctime/clock/

Адаптировано из их примера:

void runwait ( int seconds )
{
   clock_t endwait;
   endwait = clock () + seconds * CLOCKS_PER_SEC ;
   while (clock() < endwait)
   {
      /* Do stuff while waiting */
   }
}
0 голосов
/ 03 июня 2009

Если вы используете Qt, вот простой способ сделать это:

QTimer* t = new QTimer( parent ) ;
t->setInterval( 30 ) ; // in msec
t->setSingleShot( false ) ;
connect( t, SIGNAL( timeout() ), viewPort, SLOT( redraw() ) ) ;

Вам нужно будет указать viewPort и redraw(). Затем запустите таймер с t->start().

0 голосов
/ 03 июня 2009

См. QueryPerformanceCounter и QueryPerformanceFrequency

...