2012-02-10 2 views
2

Я играю вокруг нового стандарта C++. Я пишу тест, чтобы наблюдать за поведением алгоритмов планирования и видеть, что происходит с потоками. Учитывая время переключения контекста, я ожидал real время ожидания для определенного потока будет немного больше значения, указанного функцией std::this_thread::sleep_for(). Но на удивление это иногда даже меньше, чем время сна! Я не могу понять, почему это происходит, или то, что я делаю неправильно ...Wait in C++ 0x многопоточность

#include <iostream> 
#include <thread> 
#include <random> 
#include <vector> 
#include <functional> 
#include <math.h> 
#include <unistd.h> 
#include <sys/time.h> 

void heavy_job() 
{ 
    // here we're doing some kind of time-consuming job.. 
    int j=0; 
    while(j<1000) 
    { 
     int* a=new int[100]; 
     for(int i=0; i<100; ++i) 
      a[i] = i; 
     delete[] a; 
     for(double x=0;x<10000;x+=0.1) 
      sqrt(x); 
     ++j; 
    } 
    std::cout << "heavy job finished" << std::endl; 
} 

void light_job(const std::vector<int>& wait) 
{ 
    struct timeval start, end; 
    long utime, seconds, useconds; 
    std::cout << std::showpos; 
    for(std::vector<int>::const_iterator i = wait.begin(); 
     i!=wait.end();++i) 
    { 
     gettimeofday(&start, NULL); 
     std::this_thread::sleep_for(std::chrono::microseconds(*i)); 
     gettimeofday(&end, NULL); 
     seconds = end.tv_sec - start.tv_sec; 
     useconds = end.tv_usec - start.tv_usec; 
     utime = ((seconds) * 1000 + useconds/1000.0); 
     double delay = *i - utime*1000; 
     std::cout << "delay: " << delay/1000.0 << std::endl; 
    } 
} 

int main() 
{ 
    std::vector<int> wait_times; 
    std::uniform_int_distribution<unsigned int> unif; 
    std::random_device rd; 
    std::mt19937 engine(rd()); 
    std::function<unsigned int()> rnd = std::bind(unif, engine); 
    for(int i=0;i<1000;++i) 
     wait_times.push_back(rnd()%100000+1); // random sleep time between 1 and 1 million µs 
    std::thread heavy(heavy_job); 
    std::thread light(light_job,wait_times); 
    light.join(); 
    heavy.join(); 
    return 0; 
} 

выхода на моей машине Core-i5 Intel:

..... 
delay: +0.713 
delay: +0.509 
delay: -0.008 // ! 
delay: -0.043 // !! 
delay: +0.409 
delay: +0.202 
delay: +0.077 
delay: -0.027 // ? 
delay: +0.108 
delay: +0.71 
delay: +0.498 
delay: +0.239 
delay: +0.838 
delay: -0.017 // also ! 
delay: +0.157 
+3

Считаете ли вы, что ваш код времени является виноватым? –

ответ

3

Вашего код синхронизация является причиной интегрального усечения ,

utime = ((seconds) * 1000 + useconds/1000.0); 
double delay = *i - utime*1000; 

Предположим, что ваше время ожидания было 888888 микросекунд, и вы спите именно за эту сумму. seconds будет 0 и useconds будет 888888. После деления на 1000.0 вы получаете 888.888. Затем вы добавляете 0*1000, все еще уступая 888.888. Затем он назначается на длинный, оставляя вас с 888 и кажущейся задержкой 888.888 - 888 = 0.888.

Вы должны обновить utime, чтобы на самом деле хранить микросекунды, чтобы вы не получили усечение, а также потому, что имя подразумевает, что устройство находится в микросекундах, точно так же, как useconds. Что-то вроде:

long utime = seconds * 1000000 + useconds; 

У вас также есть расчет вычетов назад. Не обращая внимания на последствия усечения, она должна быть:

double delay = utime*1000 - *i; 
std::cout << "delay: " << delay/1000.0 << std::endl; 

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

+6

Umm ... и после того, как вы освоили использование ошибки с ошибкой 'timeval', используйте один из« std :: chrono :: clocks »для измерения прошедшего времени! Они легки, и когда вы их вычитаете, вы получаете 'chrono :: durations', которые не так склонны к ошибкам. Если вы вручную конвертируете единицы времени, вы делаете это неправильно. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm#Clocks –

+0

+1: I lol'd .... –

+0

Ooops ... Спасибо! –