【问题标题】:pthread_cond_timedwait()pthread_cond_timedwait()
【发布时间】:2010-12-01 23:47:36
【问题描述】:
void wait(int timeInMs)
{
    struct timespec timeToWait;
    timeToWait.tv_sec = 5;
    timeToWait.tv_nsec = timeInMs*1000;

    int rt;

    pthread_mutex_lock(&fakeMutex);
    rt = pthread_cond_timedwait(&fakeCond, &fakeMutex, &timeToWait);
    pthread_mutex_unlock(&fakeMutex);
}

我正在使用此代码尝试让线程等待一段时间,但它根本不起作用。没有错误,只是不会让程序执行得更慢。

我在想也许每个线程都需要有自己的条件和互斥锁,但这对我来说真的没有意义。

【问题讨论】:

  • 这个例子没关系,但是 nsec = 1,000,000 * msec.

标签: c pthreads


【解决方案1】:

pthread_cond_timedwait 函数需要绝对时间,而不是相对时间。您想要停止等待需要的时间,而不是您想要等待的时间。

【讨论】:

    【解决方案2】:

    使用任何睡眠变体,都无法保证行为。所有线程也可以休眠,因为内核不知道不同的线程。

    pthread_cond_timedwait 是一种更安全、更清洁的解决方案。您错误地使用了 API。这是一个更好的例子:

    pthread_mutex_t fakeMutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t fakeCond = PTHREAD_COND_INITIALIZER;
    
    void mywait(int timeInMs)
    {
        struct timespec timeToWait;
        struct timeval now;
        int rt;
    
        gettimeofday(&now,NULL);
    
    
        timeToWait.tv_sec = now.tv_sec+5;
        timeToWait.tv_nsec = (now.tv_usec+1000UL*timeInMs)*1000UL;
    
        pthread_mutex_lock(&fakeMutex);
        rt = pthread_cond_timedwait(&fakeCond, &fakeMutex, &timeToWait);
        pthread_mutex_unlock(&fakeMutex);
        printf("\nDone\n");
    }
    
    void* fun(void* arg)
    {
        printf("\nIn thread\n");
        mywait(1000);
    }
    
    int main()
    {
        pthread_t thread;
        void *ret;
    
        pthread_create(&thread, NULL, fun, NULL);
        pthread_join(thread,&ret);
    }
    

    您需要指定从当前时间开始等待多长时间。由于您只告诉了 5 秒和一些纳秒,它发现时间已经过去并且没有等待......如果还有任何疑问,请告诉我。

    【讨论】:

    • 对我来说,gettimeofday(&now,NULL) 不起作用,但它起作用了(200 毫秒):clock_gettime(CLOCK_REALTIME, &timeToWait); timeToWait.tv_nsec += 200000000UL; timeToWait.tv_nsec %= 1000000000UL; timeToWait.tv_sec += timeToWait.tv_nsec
    【解决方案3】:

    pthread_cond_timedwait 使用绝对时间,所以需要:

    • 使用 gettimeofday 检索当前时间。
    • timespec.tv_nsec 为纳秒,不能大于 1 秒。
    • timeval.tv_usec 是微秒(1000 纳秒)。
    • timeInMs 是毫秒:1 毫秒 = 1000 微秒 = 1000 * 1000 纳秒。

      void wait(int timeInMs)
      {
          struct timeval tv;
          struct timespec ts;
      
          gettimeofday(&tv, NULL);
          ts.tv_sec = time(NULL) + timeInMs / 1000;
          ts.tv_nsec = tv.tv_usec * 1000 + 1000 * 1000 * (timeInMs % 1000);
          ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000);
          ts.tv_nsec %= (1000 * 1000 * 1000);
      
          int n = pthread_cond_timedwait(&condition, &mutex, &ts);
          if (n == 0)
              // TODO: singaled
          else if (n == ETIMEDOUT)
              // TODO: Time out.
      }
      

    【讨论】:

      【解决方案4】:

      考虑到您正在使用 timespec,而您的目标不是同步,而是等待,我建议 nanosleep。

      #include <time.h>
      
      .
      .
      .
      
        struct timespec remain;
        remain.tv_sec = 5;
        remain.tv_nsec = timeInMs * 1000;
      
        do {
          if ( nanosleep( &remain, &remain ) == 0 || errno != EINTR ) {
            break;
          }
        } while ( 1 );
      
      .
      .
      .
      

      【讨论】:

        【解决方案5】:

        该代码不会休眠,它会检查一个条件一段时间。因为你可能没有设置 cond ok 它只是立即返回。

        如果您不愿意围绕信号同步线程,那么 pthread_cond _wait 不是您所需要的。检查here 条件变量是如何工作的。

        如果您想以秒精度睡眠,请使用sleep

        如果您想以微秒精度睡眠,请使用 select 和 timevals。

        【讨论】:

        • 但是 sleep 会停止整个进程,我需要线程等待。
        • 对读、写、异常参数使用带有 timeval 和 NULL 的“select”。请注意,以这种方式使用 select 仅适用于 linux,在 windows 中,如果仅提供 timeval 参数,则 select 立即返回
        【解决方案6】:

        主要参考:http://pubs.opengroup.org/onlinepubs/009695299/functions/pthread_cond_timedwait.html

        修复上述andrewrk的代码

        我可以确认Adrian May gettimeofday 无法正常运行! andrewrk 在这样的无限线程中的代码行为

        static void * thread_infinite(void * unused) {
        while (1) {
                // compute stuff
                mywait(5);
        }
        

        是不可预测的:它运行大约 700 倍,直到它阻塞!

        andrewrk的代码正确版本是:

        pthread_mutex_t fakeMutex = PTHREAD_MUTEX_INITIALIZER;
        pthread_cond_t fakeCond = PTHREAD_COND_INITIALIZER;
        
        void mywait(int timeInS)
        {
            struct timespec ts;
            struct timeval now;
            int rt = 0;
        
        //    gettimeofday(&now,NULL); // DOES NOT FUNCTION CORRECTLY
        //    timeToWait.tv_sec = now.tv_sec+5;
        //    timeToWait.tv_nsec = (now.tv_usec+1000UL*timeInMs)*1000UL;
        
            clock_gettime(CLOCK_REALTIME, &ts);
            ts.tv_sec += timeInS;
        
            pthread_mutex_lock(&fakeMutex);
        
            do {
                rt = pthread_cond_timedwait(&fakeCond, &fakeMutex, &ts);
                }
            while (rt == 0);
        
            pthread_mutex_unlock(&fakeMutex);
        }
        

        【讨论】:

        • 这是唯一有效的答案,很高兴您修复了获得最多赞的帖子。
        • 感谢@JohnJesus 的测试和确认!
        【解决方案7】:

        这是一个示例,我从主循环创建了一个线程,该线程扫描目录并超时 5 秒。并且来自线程的信号发生使用一个全局的条件变量。我们一直在检查线程中的这个信号:

            pthread_cond_t C_KISU_SwagntUtilityBase::m_cond; /*Global variable*/
        /*Inside main function*/    
        /*Local variables*/
                  pthread_condattr_t l_attr;
                  pthread_condattr_init(&l_attr);
                  pthread_condattr_setclock(&l_attr, CLOCK_MONOTONIC);
                  pthread_cond_init(&C_KISU_SwagntUtilityBase::m_cond, &l_attr);
        
                  Int32 l_threadid = pthread_create(&l_updatethread,NULL,C_KISU_SwagntUtilityBase::ThreadScanDirectoryByFilter,&l_filer);
                  if(CMP_ZERO == l_threadid)
                  {
                    pthread_mutex_t l_mutex = PTHREAD_MUTEX_INITIALIZER;
                    struct timespec l_ts;
                    if (clock_gettime(CLOCK_MONOTONIC, &l_ts) == INIT_NEGONE)
                    {
                     /* Handle error */
                    }
                    printf("\n Setting max time to  run ThreadScanDirectoryByFilter as 5 second"));
                    l_ts.tv_sec += l_filer.m_max_scan_time;
        
                    if(l_filer.m_scan_status == 0)
                    {
                      pthread_mutex_lock(&l_mutex);
                      int l_rt = pthread_cond_timedwait(&C_KISU_SwagntUtilityBase::m_cond, &l_mutex, &l_ts);
                      if (ETIMEDOUT == l_rt)
                      {
                        printf("\n timeout has happened before scan routine could finish"));
                      }
                      else if (EOK  == l_rt)
                      {
                        printf("\n Scan successful"));
                      }
                      else
                      {
                        printf("\n Unknown error while timeout condition check"));
                      }
                      pthread_mutex_unlock(&l_mutex);
                    }
                  }
                  else
                  {
                    printf("\n Error while creating thread\n");
        
                  }
        

        【讨论】:

          猜你喜欢
          • 2012-12-24
          • 2014-02-13
          • 1970-01-01
          • 2010-10-14
          • 2013-04-07
          • 2018-02-11
          • 2012-07-30
          • 2020-03-25
          • 1970-01-01
          相关资源
          最近更新 更多