2012-08-10 36 views
12

Tôi đã đọc qua thực hiện STL của tôi (chuẩn vấn đề g++ 4.6.2) và đi qua bit này của tình trạng chủng tộc bên trong condition_variable:Thực hiện timed_wait condition_variable đúng

template<typename _Rep, typename _Period> 
cv_status 
wait_for(unique_lock<mutex>& __lock, 
     const chrono::duration<_Rep, _Period>& __rtime) 
{ 
    return wait_until(__lock, __clock_t::now() + __rtime); 
} 

__clock_t là một std::chrono::system_clock, chúng tôi gắn liền với whims của những thứ như NTP (nếu đồng hồ được di chuyển trở lại bởi một ngày sau khi __clock_t::now() + __rtime, sau đó chúng tôi sẽ chờ đợi một ngày).

C++ chuẩn (30.5.1) dường như làm cho nó đúng:

Effects: như thể

return wait_until(lock, chrono::steady_clock::now() + rel_time);

thực hiện condition_variable Boost vừa thể hiện cùng vấn đề:

template<typename duration_type> 
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration) 
{ 
    return timed_wait(m,get_system_time()+wait_duration); 
} 

Trong thực tế, việc thực hiện pthreads tiềm ẩn có vẻ là vấn đề:

int pthread_cond_timedwait(pthread_cond_t *restrict cond, 
    pthread_mutex_t *restrict mutex, 
    const struct timespec *restrict abstime); 

abstime được quy định như "thời gian hệ thống," không phải là một đồng hồ đơn điệu.

Vì vậy, câu hỏi của tôi là: Làm thế nào để thực hiện một cái gì đó như std::condition_variable::wait_for chính xác? Có triển khai hiện tại nào nhận được quyền này không? Hay tôi đang thiếu một cái gì đó?

+0

Lưu ý: Trong nội bộ, 'pthread_cond_timedwait' sử dụng' gettimeofday', không có thật nếu bạn muốn hết giờ trong thời gian bạn chỉ định: http://sourceware.org/git/?p=glibc.git;a=blob; f = nptl/pthread_cond_timedwait.c; h = 7278ec45b0eb0b48be50fe832fcd17ae988dca27; hb = HEAD –

+0

Có lẽ bạn buộc phải sử dụng một số bộ đếm thời gian khác sử dụng đồng hồ đơn điệu, và sau đó đánh thức người phục vụ nếu nó hết hạn trước khi người bồi bàn hủy bỏ. – jxh

+0

Nếu tôi phải đi xa đến mức đó (điều mà tôi hết sức hy vọng là không), tôi chỉ muốn thực hiện một sự chờ đợi trong hàm 'wait_for' của mình (có vẻ như' sleep_for' của tôi không có vấn đề đó, vì 'nanosleep' không có cùng một vấn đề vì nó sử dụng đúng' CLOCK_MONOTONIC'). –

Trả lời

8

Bí quyết là sử dụng số pthread_condattr_setclock để thông báo cho pthread_condattr_t để sử dụng CLOCK_MONOTONIC. Mã C để thực hiện điều này khá đơn giản:

#include <time.h> 
#include <pthread.h> 

#include <errno.h> 
#include <stdio.h> 

int main() 
{ 
    // Set the clock to be CLOCK_MONOTONIC 
    pthread_condattr_t attr; 
    pthread_condattr_init(&attr); 
    if (int err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) 
    { 
     printf("Error setting clock: %d\n", err); 
    } 

    // Now we can initialize the pthreads objects with that condattr 
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 
    pthread_cond_t cond; 
    pthread_cond_init(&cond, &attr); 

    // when getting the time, we must poll from CLOCK_MONOTONIC 
    struct timespec timeout; 
    struct timespec now; 
    clock_gettime(CLOCK_MONOTONIC, &now); 
    timeout.tv_sec = now.tv_sec + 5; 
    timeout.tv_nsec = now.tv_nsec; 

    // business as usual... 
    pthread_mutex_lock(&mutex); 
    int rc = pthread_cond_timedwait(&cond, &mutex, &timeout); 
    if (rc == ETIMEDOUT) 
     printf("Success!\n"); 
    else 
     printf("Got return that wasn't timeout: %d\n", rc); 
    pthread_mutex_unlock(&mutex); 

    return 0; 
} 

Tôi sẽ để nguyên trạng thái này trong một thời gian vì ai đó có thể có câu trả lời dễ dàng hơn. Điều tôi không hài lòng ở đây là nó có nghĩa là wait_until khó thực hiện với đồng hồ thời gian thực (giải pháp tốt nhất của tôi là chuyển đổi số Clock được cung cấp trong số time_point vào thời gian của steady_clock và đi từ ở đó ... nó vẫn còn tùy thuộc vào điều kiện cuộc đua thay đổi thời gian, nhưng nếu bạn đang xác định thời gian chờ trong thời gian thực, bạn đã mắc phải một sai lầm khủng khiếp).

+0

Tôi nghi ngờ rằng có một câu trả lời dễ dàng hơn vì nó là một hạn chế của API POSIX. Lưu ý rằng không chỉ 'condition_variable' có vấn đề với thời gian chờ đợi nhưng' mutex' cũng có vấn đề này. Hơn nữa đối với mutexes tình hình thậm chí còn tồi tệ hơn vì không có API như 'pthread_mutexattr_setclock': http://stackoverflow.com/q/14248033/5447906. –

Các vấn đề liên quan