Это ошибка при подсчете времени? Или как можно это обосновать?

Я разрабатываю таймер, который функционирует в отдельном потоке. У меня уже есть две функции: первая использует условную переменную для случаев, когда длительность превышает 100 мс, и она работает корректно. Во второй функции я решил не использовать условную переменную, а реализовать ожидание через цикл с прямым подсчетом времени. 

Вот код для второго способа: 
<pre><code class="cpp">void Timer::WaitByYield()
{
	auto start = high_resolution_clock::now();
	auto time = 0us;
	do
	{
		std::this_thread::yield();
		time += duration_cast&lt;microseconds&gt;(high_resolution_clock::now() - start);
		start = high_resolution_clock::now();
		//std::cout &lt;&lt; duration_cast&lt;milliseconds&gt;(time) &lt;&lt; std::endl;
	}
	while(time &lt; Duration &amp;&amp; !_isPaused);

	_isElapsed = !_isPaused;
}</code></pre> 

В главной функции я использую следующий код: 
<pre><code class="cpp">using namespace std::chrono_literals;
using namespace std::chrono;

int main()
{
	Sgl::Timer t(10ms);
	t.Start();

	auto start = high_resolution_clock::now();
	while(!t.Elapsed())
	{

	}
	std::cout &lt;&lt; "Elapsed time: ";
	std::cout &lt;&lt; duration_cast&lt;milliseconds&gt;(high_resolution_clock::now() - start);
}</code></pre> 

Проблема заключается в выводе, если закомментировать строку 
<pre><code class="cpp">//std::cout &lt;&lt; duration_cast&lt;milliseconds&gt;(time) &lt;&lt; std::endl;</code></pre>. 
  • 26 сентября 2024 г. 14:33
Ответы на вопрос 1
Ваша проблема может быть связана с тем, как вы измеряете и накапливаете время в функции `WaitByYield()`. Давайте рассмотрим основные моменты:

1. **Проблема с подсчетом времени**: Ваша функция `WaitByYield()` должна корректно подсчитывать прошедшее время, однако вы используете `start` для измерения времени в каждой итерации цикла. После того как вы вычисляете промежуток времени, вы сразу обновляете `start`, что может привести к неполным или неверным значениям. Вместо этого вам следует делать это один раз в начале и затем только обновлять `time`.

2. **Обновление времени**: Вместо того, чтобы каждый раз накапливать `time`, вы можете просто определить текущее время в начале и вычесть из него значение `start`, чтобы получить прошедшее время более эффективно. 

3. **Неэффективное использование `std::this_thread::yield()`**: Ваша реализация с вызываемым `yield()` в цикле может быть неэффективной, если цикл выполняется слишком быстро. Это может привести к высокому потреблению ресурсов CPU.

4. **Возможные проблемы с параллелизмом**: Теперь, когда вы используете отдельный поток для работы с таймером, убедитесь, что вы правильно синхронизируете доступ к общим переменным (таким как `_isElapsed` и `_isPaused`), чтобы избежать условных гонок.

Вот как можно переписать ваш код для более правильного счисления времени:

```cpp
void Timer::WaitByYield()
{
    auto start = high_resolution_clock::now();
    auto end = start + Duration;

    while (!_isPaused && high_resolution_clock::now() < end)
    {
        std::this_thread::yield();
    }

    _isElapsed = !_isPaused;
}
```

В вашем `main()`, вы можете оставить код, как он есть, но добавьте соответствующие проверки:

```cpp
int main()
{
    using namespace std::chrono_literals;
    using namespace std::chrono;

    Sgl::Timer t(10ms);
    t.Start();

    auto start = high_resolution_clock::now();
    while (!t.Elapsed())
    {
        // Возможно, здесь тоже стоит добавить yield(), чтобы снизить нагрузку на CPU
        std::this_thread::yield();
    }

    std::cout << "Elapsed time: ";
    std::cout << duration_cast<milliseconds>(high_resolution_clock::now() - start).count() << " ms" << std::endl;

    return 0;
}
```

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