2012-06-25 48 views
4

不幸的是cygwin的GCC 4.5.3並行線程庫實現不支持POSIX標準函數cygwin的pthread_mutex_timedlock替代

int pthread_mutex_timedlock(pthread_mutex_t* mutex, struct timespec* abstime); 

有沒有人一個好主意,如何實現一個很好的解決方法在一個互斥體包裝類此方法?可能會使用pthread_mutex_trylock()(基於毫秒)nanosleep()調用? 我沒有對後者的想法感覺不錯,但不管怎麼說,C++實現看起來是這樣的:

bool MyPosixMutexWrapper::try_lock(const TimeDuration<>& timeout) 
{ 
    if(valid) 
    { 
     if(timeout == TimeDuration<>::Zero) 
     { 
      if(pthread_mutex_trylock(&mutexHandle) == 0) 
      { 
       return true; 
      } 
     } 
     else 
     { 
      struct timespec now; 
      clock_gettime(CLOCK_REALTIME,&now); 
      TimeDuration<> tnow(now); 
      tnow += timeout; 
      struct timespec until = tnow.getNativeValue(); 
#if defined(_POSIX_TIMEOUTS) 
      if(pthread_mutex_timedlock(&mutexHandle,&until) == 0) 
      { 
       return true; 
      } 
#else 
      long milliseconds = timeout.milliseconds(); 
      while(milliseconds > 0) 
      { 
       if(pthread_mutex_trylock(&mutexHandle) == 0) 
       { 
        return true; 
       } 

       struct timespec interval; 
       struct timespec remaining; 
       interval.tv_sec = 0; 
       interval.tv_nsec = 1000000; 
       do 
       { 
        remaining.tv_sec = 0; 
        remaining.tv_nsec = 0; 
        if(nanosleep(&interval,&remaining) < 0) 
        { 
         if(errno == EINTR) 
         { 
          interval.tv_sec = remaining.tv_sec; 
          interval.tv_nsec = remaining.tv_nsec; 
         } 
         else 
         { 
          return false; 
         } 
        } 
        clock_gettime(CLOCK_REALTIME,&now); 
        tnow = TimeDuration<>(now); 
        if(tnow >= TimeDuration(until)) 
        { 
          return pthread_mutex_trylock(&mutexHandle) == 0; 
        } 
       } while(remaining.tv_sec > 0 || remaining.tv_nsec > 0); 
       --milliseconds; 
      } 
#endif 
     } 
    } 
    return pthread_mutex_trylock(&mutexHandle) == 0; 
} 

有誰有這個代碼的一個更好的主意或改進措施?

+0

您可以使用Windows互斥鎖代替pthread互斥鎖,並在適當的超時時間內使用'WaitForSingleObject'。但是Windows互斥體非常霸道,需要針對所有情況的系統調用,甚至是無可爭議的鎖定,所以除了必須編寫所有新代碼來處理它們之外,您可能會遇到性能問題。 –

+0

@AdamRosenfield:我希望有一個'POSIX兼容'的實現,'_POSIX_TIMEOUTS'指示'pthread_mutex_timedlock()'函數是否可用。我不想在此代碼中使用Windows本機解決方案。 –

+0

由於我已經害怕,所提議的實現在Cygwin環境下不能很好地工作。儘管我已經改進了代碼來檢查超時... –

回答

3

我的建議是使用pthread_cond_timedwait來模擬你的定時鎖。這裏的訣竅是timed_mutex_永遠不會持續很長時間,因爲等待timed_cond_釋放鎖定。在locked_設置或未設置後,timed_mutex_也會立即釋放。

struct MutexGuard { 
    pthread_mutex_t &mutex_; 
    MutexGuard (pthread_mutex_t &m) : mutex_(m) { 
     pthread_mutex_lock(&mutex_); 
    } 
    ~MutexGuard() { 
     pthread_mutex_unlock(&mutex_); 
    } 
}; 

struct TimedMutex { 
    pthread_mutex_t timed_mutex_; 
    pthread_cond_t timed_cond_; 
    bool locked_; 

    TimedMutex() 
     : timed_mutex_(), timed_cond_(), locked_(false) { 
     pthread_mutex_init(&timed_mutex_, 0); 
     pthread_cond_init(&timed_cond_, 0); 
    } 

    ~TimedMutex() { 
     pthread_cond_destroy(&timed_cond_); 
     pthread_mutex_destroy(&timed_mutex_); 
    } 

    int lock (const struct timespec *t) { 
     MutexGuard g(timed_mutex_); 
     while (locked_) { 
      int r = pthread_cond_timedwait(&timed_cond_, &timed_mutex_, t); 
      if (r < 0) return r; 
     } 
     locked_ = true; 
     return 0; 
    } 

    void lock() { 
     MutexGuard g(timed_mutex_); 
     while (locked_) { 
      pthread_cond_wait(&timed_cond_, &timed_mutex_); 
     } 
     locked_ = true; 
    } 

    void unlock() { 
     MutexGuard g(timed_mutex_); 
     locked_ = false; 
     pthread_cond_signal(&timed_cond_); 
    } 
}; 
+0

Thx,你的答案看起來很有希望。只是爲了好奇:這是cx11標準爲互斥和timedmutex提供單獨類型的原因嗎?因爲後者可能需要額外的資源來執行它? –

+0

@ g-makulik:恐怕我不知道C++ 11委員會決定背後的理由。但是,我想它允許程序員從庫中包含一小部分代碼以完成工作,並且使用庫編寫器來提供提供功能的最緊密的實現。 – jxh

+1

我不明白你爲什麼要在這裏使用兩個不同的互斥體,直接的解決方案是通過使用一個互斥體和一個條件變量來構建自己的定時互斥體類型。此外,這種解決方案在爭用時可能會非常緩慢。 –