Что может вызвать такое странное поведение, когда два потока спят одновременно? - PullRequest
0 голосов
/ 24 января 2011

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

Если я выполняю sleep () только в потоке рендеринга, то в течение 10 миллисекунд FPS обычно равен 100.

Если я вообще не сплю в потоке рендеринга и сплю в потоке событий, поток рендеринга вообще не замедляется.

Но, если я сплю 10 миллисекунд в потоке рендеринга и 10 в потоке событий, FPS не 100, а ниже, около 84! (обратите внимание, что это то же самое, даже если блокировки мьютекса полностью удалены)

(Если ни один из них не спит, он обычно поднимается).

Что может вызвать такое поведение?

-

Используемая команда сна - Sleep () для окон или SDL_Delay () (которая, вероятно, заканчивается Sleep () для окон).

Ответы [ 3 ]

1 голос
/ 26 января 2011

Мне кажется, я нашел ответ (собственный ответ).

Спящий режим не гарантированно ожидает определенного периода, но он будет ожидать как минимум определенное время из-за планирования ОС.

Лучшим подходом было бы вычислить фактическое время, прошедшее явно (и разрешить выполнение через него, только если прошло определенное время).

0 голосов
/ 25 января 2011

Поведение будет зависеть от многих факторов, таких как версия ОС (например, Win7 против Win XP) и количество ядер.Если у вас есть два ядра и два потока без объектов синхронизации, они должны работать одновременно, и Sleep () в одном потоке не должен влиять на другой (по большей части).

Похоже, у вас есть другая синхронизация междупотоки, потому что в противном случае, когда вы вообще не спите в потоке рендеринга, вы должны работать со скоростью> 100FPS, нет?

В случае, если синхронизация абсолютно отсутствует, в зависимости от объема обработки в двух потокахих использование Sleep () может увеличить вероятность конфликта для одноядерной системы.То есть, если только один поток вызывает Sleep (), обычно, скорее всего, ему будут даны следующие кванты после того, как он проснется и при условии, что он выполняет очень мало обработки, то есть сразу выдает, такое поведение продолжится.Если два потока вызывают Sleep (), существует некоторая вероятность, что они проснутся в одних и тех же квантах, и если хотя бы одному из них потребуется выполнить какой-либо объем обработки, другой будет задержан, и наблюдаемая частота будет ниже.Это должно применяться только в том случае, если доступно одно ядро ​​для запуска двух потоков.

Если вы хотите поддерживать частоту обновления 100FPS, вы должны отслеживать время следующего запланированного обновления и только Sleep в течение оставшегося времени.Это гарантирует, что даже если ваш поток столкнется с каким-либо другим потоком для квантов ЦП, вы сможете сохранить скорость (при условии, что процессорного времени достаточно для всей обработки).Что-то вроде:

DWORD next_frame_time = GetTickCount(); // Milli-seconds. Note the resolution of GetTickCount()
while(1)
{
  next_frame_time += 10; // Time of next frame update in ms
  DWORD wait_for = next_frame_time - GetTickCount(); // How much time remains to next update
  if( wait_for < 11 ) // A simplistic test for the case where we're already too late
  {
    Sleep(wait_for);
  }
// Do periodic processing here
}

В зависимости от целевой ОС и ваших требований к точности, вы можете использовать функцию времени с более высоким разрешением, такую ​​как QueryPerformanceCounter ().Приведенный выше код не будет хорошо работать в Windows XP, где разрешение GetTickCount () составляет ~ 16 мс, но должно работать в Win7 - это в основном для иллюстрации моей точки зрения, а не для буквального копирования во всех ситуациях.

0 голосов
/ 25 января 2011

Потоки работают асинхронно, если вы не синхронизируете их, и будут планироваться в соответствии с политикой планирования ОС.Я хотел бы предположить, что поведение в лучшем случае будет недетерминированным (если, возможно, вы не работали в ОСРВ).

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...