Каков наилучший способ выйти из цикла по истечении 30 мс на С++?
Автор вопроса: Neil GОтветов: 9
Каков наилучший способ выйти из цикла как можно ближе к 30 мс в С++. Ускорение опроса: microsec_clock ? Опрос QTime ? Что-то другое?
Что-то типа:
A = now;
for (blah; blah; blah) {
Blah();
if (now - A > 30000)
break;
}
Он должен работать в Linux, OS X и Windows.
Вычисления в цикле предназначены для обновления симуляции. Каждые 30 мс я хотел бы обновить область просмотра.
добавил тег qt к вашему вопросу, как вы упомянули QTime Idan K 03.06.2009
Вы имеете в виду любое время после 30 мс или как можно ближе к 30 мс? Max Lybbert 03.06.2009
Может быть, это поможет рассказать, чего вы действительно хотите достичь. lothar 03.06.2009
Возможно, вы также захотите добавить, какое оборудование/ОС вы используете. Различные аппаратные платформы предоставляют счетчики времени с разной точностью. J. Polfer 03.06.2009
Ответил на комментарии в вопросе. Neil G 03.06.2009
Спасибо всем за отличные ответы! Для этого существует StackOverflow. Три верхних ответа - это все решения: используйте clock(), используйте потоки и опрашивайте аппаратные часы. Первое решение требует наименьшей работы и является моим временным решением, пока я не разработаю многопоточную модель. (Удивительно, но никто не говорил о boost::microsec_timer или как там это называется.) Neil G 04.06.2009
void runwait ( int seconds )
{
clock_t endwait;
endwait = clock () + seconds * CLOCKS_PER_SEC ;
while (clock() < endwait)
{
/* Do stuff while waiting */
}
}
Ответ 2 · рейтинг 11 · Juliano
Вычисления в цикле предназначены для обновления симуляции. Каждые 30 мс я хотел бы обновить окно просмотра.
Рассматривали ли вы использование потоков? То, что вы описываете, кажется прекрасным примером того, почему вы должны использовать потоки вместо таймеров.
Основной поток процесса продолжает заботиться о пользовательском интерфейсе и имеет QTimer, установленный на 30 мс, для его обновления. Он блокирует QMutex для доступа к данным, выполняет обновление и освобождает мьютекс.
Второй поток (см. QThread) выполняет моделирование. Для каждого цикла он блокирует QMutex, выполняет вычисления и освобождает мьютекс, когда данные находятся в стабильном состоянии (подходит для обновления пользовательского интерфейса).
С ростом популярности многоядерных процессоров вам следует все больше и больше думать об использовании потоков, а не об использовании таймеров. Ваши приложения автоматически выигрывают от повышенной мощности (многоядерность) новых процессоров.
Ответ 3 · рейтинг 4 · Ariya Hidayat
Хотя это не отвечает на вопрос, это может дать другой взгляд на решение. Как насчет размещения кода моделирования и пользовательского интерфейса в разных потоках? Если вы используете Qt, периодическое обновление можно реализовать с помощью таймера или даже QThread::msleep( )а>. Вы можете адаптировать пример Мандельброта с резьбой в соответствии со своими потребностями.
Ответ 4 · рейтинг 2 · SingleNegationElimination
Если вам нужно выполнить работу до истечения определенного времени, тогда ответ docflabby точен. Однако, если вам нужно просто подождать, ничего не делая, пока не истечет указанное время, вам следует использовать usleep()
Ответ 5 · рейтинг 2 · James
Короткий ответ: в общем случае вы не можете, но можете, если работаете на правильной ОС или на правильном оборудовании.
Вы можете получить БЛИЗКО 30 мс на всех ОС, используя вызов сборки в системах Intel и что-то еще в других архитектурах. Я откопаю ссылку и отредактирую ответ, чтобы включить код, когда найду его.
Проблема заключается в алгоритме разделения времени и в том, насколько близко вы находитесь к концу своего временного отрезка в многозадачной ОС.
В некоторых операционных системах реального времени есть системный вызов в системной библиотеке, который вы можете сделать, но я не уверен, что это будет за вызов.
У VonC есть комментарий с ассемблерным кодом процессорного таймера.
Ответ 6 · рейтинг 2 · J. Polfer
Согласно вашему вопросу, каждые 30 мс вы хотите обновлять окно просмотра. Однажды я написал похожее приложение, которое проверяло оборудование каждые 500 мс на наличие похожих вещей. Хотя это не дает прямого ответа на ваш вопрос, у меня есть следующие дополнения:
Вы уверены, что Blah() для обновления области просмотра может выполняться менее чем за 30 мс в каждом экземпляре?
Больше похоже на то, что запуск Blah() будет лучше выполняться обратным вызовом таймера.
Очень сложно найти библиотечный объект таймера, который будет устанавливать интервал в 30 мс для выполнения обновлений в графическом фреймворке. В Windows XP я обнаружил, что стандартный API-таймер Win32, который отправляет оконные сообщения по истечении интервала таймера, даже на 2-ГГц P4, не может выполнять обновления быстрее, чем с интервалом 300 мс, независимо от того, насколько малый интервал времени я установил на таймер. Хотя в Win32 API были доступны высокопроизводительные таймеры, у них есть много ограничений, а именно то, что вы не можете выполнять какие-либо IPC (например, виджеты обновления пользовательского интерфейса) в цикле, подобном тому, который вы указали выше.
По сути, в результате вы должны очень тщательно спланировать, как вы хотите, чтобы обновления происходили. Возможно, вам придется использовать потоки и посмотреть, как вы хотите обновить область просмотра.
Просто есть о чем подумать. Они застали меня врасплох, когда я работал над своим проектом. Если вы уже обдумали эти вещи, пожалуйста, не обращайте внимания на мой ответ :0).
Ответ 7 · рейтинг 2 · Community
Вы можете подумать об обновлении окна просмотра каждые N шагов моделирования, а не каждые K миллисекунд. Если это (скажем) серьезное коммерческое приложение, то вы, вероятно, захотите пойти по многопоточному маршруту, предложенному в другом месте, но если (скажем) это для личного использования или использования ограниченной аудиторией и что вас действительно интересует - это детали того, что вы моделируете, тогда каждый-N-шаг прост, портативен и вполне может быть достаточно хорош, чтобы с ним можно было справиться.
Ответ 8 · gatorfax
См. QueryPerformanceCounter и QueryPerformanceFrequency.
Ответ 9 · swongu
Если вы используете 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().