Временные различия с std:: chrono:: system_clock/std:: chrono:: high_resolution_clock

Рассмотрим следующий фрагмент кода

#include <chrono>
#include <iostream>
#include <thread>

int main()
{
   using std::chrono::system_clock;
   using std::chrono::milliseconds;
   using std::chrono::nanoseconds;
   using std::chrono::duration_cast;
   const auto duration = milliseconds(100);
   const auto start = system_clock::now();
   std::this_thread::sleep_for(duration);
   const auto stop = system_clock::now();
   const auto d_correct = duration_cast<nanoseconds>(duration).count();
   const auto d_actual = duration_cast<nanoseconds>(stop - start).count();
   std::cout << "Difference is " << d_actual << ", and it should be roughly " << d_correct << "\n";
}

Что мы ожидаем, это что-то в строке

Разница составляет 100039989, и она должна быть примерно 100000000

Смотрите эту демонстрацию, где она работает абсолютно нормально.

Однако на моей машине установлено несколько компиляторов, которые, по-видимому, вызывают несогласованность в соответствии с этим ответом здесь, в разделе Переполнение стека.

Поэтому я попробовал исправить исправление: Установка правильного LD_LIBRARY_PATH. Это комбинации с результатами, которые я пробовал (среди прочего, с 4.4 и 4.6...)

g++-4.7 time.cpp -pthread -std=c++11; LD_LIBRARY_PATH=/usr/lib/gcc/i686-linux-gnu/4.7/ ./a.out

Разница равна 100126, и она должна быть примерно 100000000

g++-4.7 time.cpp -pthread -std=c++11; LD_LIBRARY_PATH=/usr/lib/gcc/i686-linux-gnu/4.8/ ./a.out

Разница составляет 100132, и она должна быть примерно 100000000

g++-4.8 time.cpp -pthread -std=c++11; LD_LIBRARY_PATH=/usr/lib/gcc/i686-linux-gnu/4.7/ ./a.out

Разница 100085953, и она должна быть примерно 100000000

g++-4.8 time.cpp -pthread -std=c++11; LD_LIBRARY_PATH=/usr/lib/gcc/i686-linux-gnu/4.8/ ./a.out

Разница равна 100156418, и она должна быть примерно 100000000

Кажется, что независимо от того, компиляция с g++-4.8 отлично работает с использованием любого из libstdc++, а компиляция с g++-4.7 приводит к нарушенной ситуации.

Неужели я делаю что-то не так в компиляторе/двоичном вызове или это ошибка в g++-4.7? (It g++-4.7.3 и g++-4.8.1, чтобы быть конкретным)

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

Ответ 1

Я не могу комментировать, но, похоже, это проблема только с функцией duration_cast... Я наткнулся на ваш сон до 1000 мс и провел его против утилиты времени. Действительно, он спит в течение 1 секунды.

#include <chrono>
#include <iostream>
#include <thread>

int main()
{
   using std::chrono::system_clock;
   using std::chrono::milliseconds;
   using std::chrono::nanoseconds;
   using std::chrono::duration_cast;
   const auto duration = milliseconds(1000);
   const auto start = system_clock::now();
   std::this_thread::sleep_for(duration);
   const auto stop = system_clock::now();
   const auto d_correct = duration_cast<nanoseconds>(duration).count();
   const auto d_actual = duration_cast<nanoseconds>(stop - start).count();
   std::cout << "Difference is " << d_actual << ", and it should be roughly " << d_correct << "\n";
}

Запустите его с помощью утилиты time:

g++-4.7 time.cpp -pthread -std=c++11; time LD_LIBRARY_PATH=/usr/lib/gcc/i686-linux-gnu/4.7/ ./a.out
Difference is 1000193, and it should be roughly 1000000000

real    0m1.004s
user    0m0.000s
sys     0m0.000s

Итак, действительно, это похоже на проблему с ABI. И моя система так же глупо об использовании более новой версии libstdС++ в качестве вашей системы. Мы можем подтвердить это с помощью ldd и/или LD_DEBUG = файлов:

ldd a.out 
    linux-vdso.so.1 =>  (0x00007fff139fe000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ff0595b7000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ff0593a1000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff059183000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff058dba000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ff058ab5000)
    /lib64/ld-linux-x86-64.so.2 (0x00007ff0598e6000)

КУРИТЬ! Это определенно не является правильным libstdС++... И ничто из этого не могло остановить его!

Мой следующий эксперимент состоял в попытке установить связь со статическим libstdС++ (http://www.trilithium.com/johan/2005/06/static-libstdc/):

ln -s `g++-4.7 -print-file-name=libstdc++.a`
g++-4.7 -static-libgcc -L. time.cpp -pthread -std=c++11; time ./a.out
Difference is 1000141417, and it should be roughly 1000000000

real    0m1.003s
user    0m0.004s
sys     0m0.000s

ВСЕ ЛУЧШЕ! Итак, в целом, вы в безопасности. В GCC 4.7 (хе-хе) нет ничего изначально неправильного, но какая неприятная проблема!

Ответ 2

попробуйте явно использовать   duration_cast (system_time:: now() - start).count()

Ответ 3

Много раз неизбежно дифференцировать код в соответствии с версией компилятора. Я бы предложил не решить разницу между 4.7 и 4.8 во время выполнения ( "уродливое" решение, о котором вы упомянули). Сделайте это во время компиляции.

#if __GNUC__ == 4 && __GNUC_MINOR__ > 7
   // your gcc 4.8 and above code here
#else
   // your gcc 4.7.x and below code here
#endif