【问题标题】:nanosleep does not work for values less than a secondnanosleep 不适用于小于一秒的值
【发布时间】:2014-09-26 16:05:08
【问题描述】:

我有一个使用nanosleep 的程序(混合C 和Fortran,虽然这似乎不相关)。但是,如果我的 timespectv_sec 值为 0,它根本不会休眠。 tv_nsec 值可能比整秒差几微秒,但它不会休眠。 (如果tv_sec1,睡一秒也没问题。)为什么会这样?

为了让事情更加混乱,具有适当值(即995000usec)的usleep 会按预期休眠大约一秒钟。

我在 RHEL 5.8 和 RHEL 6.4 机器上看到了这个问题。两者都使用gcc

这是调用 nanosleep 的函数:

void msleep(int *milliseconds)
{
    long usec;
    struct timespec sleep;
    usec = (*milliseconds) % 1000;
    sleep.tv_sec = (*milliseconds) / 1000;
    sleep.tv_nsec = 1000*usec;
    nanosleep(&sleep, NULL);
}

显然,我实际上并不需要纳秒级精度!

我还测试了一个我确实检查了返回值的版本;它始终是0(成功),因此rem 输出参数(如果被中断,则剩余时间)从未设置。

【问题讨论】:

  • strace你的程序了吗?您是否检查了nanosleep(2) 的返回并在失败时使用了errno(例如通过perror)。你运行什么内核?我有点怀疑:在我所有的应用程序中,nanosleep 都按照文档说明工作。请显示一些实际代码!
  • 您可能想向我们展示您如何调用nanosleep() 以及如何初始化您传入的结构?
  • 查看新编辑。抱歉,我应该在原帖中解释返回值。
  • 对我来说,这看起来好像你缺少 1000 一些地方:[ms]%1000=[ms] 和 [ms]*1000=[us] 但你想要 [ns],所以这应该是...tv_nsec = ((long)(milliseconds%1000)) * 1000 * 1000,不是吗?
  • usec 声明在哪里?

标签: c linux sleep


【解决方案1】:

你错过了 1000 倍。

试试这个:

#define _POSIX_C_SOURCE 199309L /* shall be >= 199309L */

#include <time.h>

void msleep(int *milliseconds)  
{
  int ms_remaining = (*milliseconds) % 1000;
  long usec = ms_remaining * 1000;
  struct timespec ts_sleep;

  ts_sleep.tv_sec = (*milliseconds) / 1000;
  ts_sleep.tv_nsec = 1000*usec;
  nanosleep(&ts_sleep, NULL);
}

更紧凑:

#define _POSIX_C_SOURCE 199309L /* shall be >= 199309L */

#include <time.h>

void msleep(int * pmilliseconds)  
{
  struct timespec ts_sleep = 
  {
    *pmilliseconds / 1000,
    (*pmilliseconds % 1000) * 1000000L
  };

  nanosleep(&ts_sleep, NULL);
}

终于有一个完整的实现,包括错误处理和nanosleep()被提前中断的情况:

#define _POSIX_C_SOURCE 199309L

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

int ms_sleep(unsigned int ms)
{
  int result = 0;

  {
    struct timespec ts_remaining =
    { 
      ms / 1000, 
      (ms % 1000) * 1000000L 
    };

    do
    {
      struct timespec ts_sleep = ts_remaining;
      result = nanosleep(&ts_sleep, &ts_remaining);
    } 
    while ((EINTR == errno) && (-1 == result));
  }

  if (-1 == result)
  {
    perror("nanosleep() failed");
  }

  return result;
}

按照包装器来满足 OP 的要求:

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

int ms_sleep(unsigned int);

void msleep(int * pms)
{
  int result = 0;

  if ((NULL == pms) || (0 > *pms)) /* Check for valid input. */
  {
    errno = EINVAL;
    result = -1;
  }
  else 
  {
    result = ms_sleep(*pms));
  }

  if (-1 == result)
  {
    perror("ms_sleep() failed");
    /* Exit and/or log error here. */
  }
}

更新(参考下面chux的评论):

假设至少C99,以上这部分代码

  struct timespec ts_sleep = 
  {
    *pmilliseconds / 1000,
    (*pmilliseconds % 1000) * 1000000L
  };

最好这样写

  struct timespec ts_sleep = 
  {
    .tv_sec = *pmilliseconds / 1000,
    .tv_nsec = (*pmilliseconds % 1000) * 1000000L
  };

不依赖struct timespec的成员顺序。

【讨论】:

  • 顺便说一句:Posix 结构的顺序是固定的吗?
  • @chux:请问您指的是哪种“订单”?
  • struct timespec ts_sleep = { *pmilliseconds / 1000, (*pmilliseconds % 1000) * 1000000L }; 仅在字段顺序固定时才有效。例如。 div_t 用于 C 兼容代码的两个字段可以按任意顺序排列。那么 Posix 是否修复了结构的字段顺序?
  • @chux:有趣的问题 - 直到现在我都认为“是”,顺序是明确定义的。在这里阅读后:pubs.opengroup.org/onlinepubs/9699919799/basedefs/time.h.html 我不再那么确定了。不过,您可能想在 SO 提出这个问题! ;-)
  • 你拥有的第三个源代码块while (EINTR == result);应该是while (result == -1 &amp;&amp; errno == EINTR);
【解决方案2】:

我按照下面的方法做了,它成功了......

#include <stdio.h>
#include <time.h>   /* Needed for struct timespec */


int nsleep(long miliseconds)
{
   struct timespec req, rem;

   if(miliseconds > 999)
   {   
        req.tv_sec = (int)(miliseconds / 1000);                            /* Must be Non-Negative */
        req.tv_nsec = (miliseconds - ((long)req.tv_sec * 1000)) * 1000000; /* Must be in range of 0 to 999999999 */
   }   
   else
   {   
        req.tv_sec = 0;                         /* Must be Non-Negative */
        req.tv_nsec = miliseconds * 1000000;    /* Must be in range of 0 to 999999999 */
   }   

   return nanosleep(&req , &rem);
}

int main()
{
   int ret = nsleep(2500);
   printf("sleep result %d\n",ret);
   return 0;
}

【讨论】:

    【解决方案3】:

    方法如下

      static void Sleep(long lMs){
           //Calculate the nanosecond
           long lRemainingMilliSecond = (lMs) % 1000;
           long lNanoSecond = lRemainingMilliSecond * 1000000;
    
           struct timespec ts_sleep,ts_remaining;
    
           ts_sleep.tv_sec = (lMs) / 1000;
           ts_sleep.tv_nsec = lNanoSecond;
           nanosleep(&ts_sleep, &ts_remaining);
    }
    

    下页更好地解释了这个概念 Convert milliseconds to timespec - GNU Porting

    【讨论】:

      猜你喜欢
      • 2017-12-15
      • 2015-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-07
      • 2020-02-29
      • 2018-11-22
      • 1970-01-01
      相关资源
      最近更新 更多