sem_timedwait 等待时间小于1s时的精确性

源代码:

 sem_t set;

 set_init(&sem,0,0);

 int i = 0;

 while(i < 100)

 {

       struct timespec ts;

       ts.tv_sec = time();

       ts.tv_nsec = 998*1000*1000;

       sem_timedwait(&sem,&ts);

 }

原意:函数循环100次,每次等待998ms。结果:函数瞬间结束

 

原因分析:

按照man 的解释使用sem_timedwait,用time()取时间,原以为是set_timedwait的精确性有问题,看来是冤枉它了。

time()函数返回当前绝对时间的秒级数据。

1、假设第一次循环之前绝对时间为1s990ms,则函数等待到1s998ms。等待时间为9ms。

     第二次设置时间:秒数仍为1s,而微秒级为998ms,这个时间已经在第一次循环到了,则函数不等待立即返回。

     以后98次相同。(统计以后的99次只运行了不到1ms,可见计算机的速度)

2、假设第一次循环之前绝对时间为1s999ms,则时间已经过了,函数不等到立即返回。

     可能以后的某个循环秒设置为2,再等待到998ms。不过这时等待时间已经不准确

 

解决方法:得到当前精确的时间,本函数可以精确到1毫秒,不过对于大部分应用已经足够了,呵呵

 sem_t set;

 set_init(&sem,0,0);

 int i = 0;

 while(i < 100)

 {

       struct timespec ts;

       struct timeval tt;

       gettimeofday(&tt,NULL);

 

       ts.tv_sec = tt.tv_sec;

       ts.tv_nsec = tt.tv_usec*1000 + x * 1000 * 1000;//这里可能造成纳秒>1000 000 000

       ts.tv_sec += ts.tv_nsec/(1000 * 1000 *1000);

       ts.tv_nsec %= (1000 * 1000 *1000);

 

       sem_timedwait(&sem,&ts);

       i++;

 }


解释以下以下代码是什么意思unsigned int g_ls_max_num = LS_PRELOAD_MAX_LS_NUM;   int g_ls_time_lsid = LS_TIME_LSID_INIT_VALUE;   unsigned int g_ls_time_debug = 0;   /* admin和ls同操作是否用锁隔离开 */   int g_ls_use_sem = 0;     offset_info_t *g_ls_time_offset[LS_PRELOAD_MAX_LS_NUM + 1] = {NULL};     static inline int gettimeofday_orig(struct timeval *tv, struct timezone *tz)   {       return g_pfn_ls_gettimeofday ? g_pfn_ls_gettimeofday(tv, tz) : DRV_ERROR; 16 Line113. g_pfn_ls_gettimeofday is true 17 Line113. Assume return here   }   static inline int settimeofday_orig(const struct timeval *tv, const struct timezone *tz)   {       return g_pfn_ls_settimeofday ? g_pfn_ls_settimeofday(tv, tz) : DRV_ERROR;   }   static inline int adjtimex_orig(struct timex *buf)   {       return g_pfn_ls_adjtimex ? g_pfn_ls_adjtimex(buf) : DRV_ERROR;   }   static inline int adjtime_orig(const struct timeval *delta, struct timeval *olddelta)   {       return g_pfn_ls_adjtime ? g_pfn_ls_adjtime(delta, olddelta) : DRV_ERROR;   }     static inline int sem_wait_timeout(sem_t *sem, int msec)   {       int ret;         while (msec > 0) { 12 Line132. msec > 0 is true           ret = sem_trywait(sem);           if (ret != -1) {               return LS_TIME_SEM_OK; 13 Line135. Assume return here           }           if (errno == EAGAIN) {               (void)usleep(USEC_IN_MSEC); /* sleep for 1ms */               msec--;           } else {               return LS_TIME_SEM_ERROR;           }       }         return LS_TIME_SEM_TIMEUP;           }       }         return (int)ret;   }     unsigned int ls_time_sem_wait_ls(int ls_id)   {       int ret = DRV_OK;         if (g_ls_use_sem == 0) { 8 Line215. g_ls_use_sem == 0 is false           return 0;       }         if (g_ls_time_offset[ls_id] && g_ls_time_offset[ls_id]->init_sem) { 9 Line219. g_ls_time_offset[ls_id] is true 10 Line219. g_ls_time_offset[ls_id] && g_ls_time_offset[ls_id]->init_sem is true           ret = sem_wait_timeout(&g_ls_time_offset[ls_id]->ls_sem, MSEC_SEMWAIT); 11 Line220. Function sem_wait_timeout is executed           if (ret == LS_TIME_SEM_OK) {               return DRV_OK; 14 Line222. Assume return here           } else if (ret == LS_TIME_SEM_TIMEUP) {               /* 如果超了,则说明LS之前异常复位,需要主动解锁并再加锁 */               if (sem_post(&g_ls_time_offset[ls_id]->ls_sem) == -1) {                   /* 一般不会进入此分支 */                   ret = errno;                   DEBUG("sem_post ls%d not success(%d), set init flag to 0.", ls_id, ret);               } else {                   /* 如果post后加锁还有问题,就直接返回 */                   return (sem_trywait(&g_ls_time_offset[ls_id]->ls_sem) == 0) ? DRV_OK : DRV_ERROR;               }   }     int settimeofday(const struct timeval *tv, const struct timezone *tz)   {       int ret;       unsigned int ls_id;       struct timeval tv_admin_old;       offset_info_t *info = NULL;       unsigned int sem_waited;         (void)memset_s(&tv_admin_old, sizeof(struct timeval), 0, sizeof(struct timeval)); 2 Line626. Function memset_s is executed         DEBUG_TRACE("setting ls[%d] time", g_ls_time_lsid);         if (g_ls_time_lsid < 0) { 4 Line630. g_ls_time_lsid < 0 is false           /* 如果lsid未初始化,使用原来的 */           return settimeofday_orig(tv, tz);       }         if (g_ls_time_lsid) { 5 Line635. g_ls_time_lsid is true           struct timeval tv_ls_old;           unsigned int sem_ret;             /* ls容器内修改间 */           info = g_ls_time_offset[g_ls_time_lsid];           /* 获取偏移失败,为提高可靠性,认为不需要偏移并直接返回 */           if (info == NULL) { 6 Line642. info == NULL is false               DEBUG("settimeofday get ls%d offset not success.", g_ls_time_lsid);               return DRV_OK;           }             sem_ret = ls_time_sem_wait_ls(g_ls_time_lsid); 7 Line647. Function ls_time_sem_wait_ls is executed             ret = gettimeofday_orig(&tv_admin_old, NULL); 15 Line649. Function gettimeofday_orig is executed           if (ret) { 18 Line650. ret is false               if (sem_ret == 0) {                   (void)ls_time_sem_post_ls(g_ls_time_lsid);               }               DEBUG("gettimeofday_orig not success %d.", ret);               return ret;           }             /* 调用ls_time_calc更新下adjtime_delta,如果有的话 */           (void)ls_time_calc(&tv_ls_old, &tv_admin_old, info);           info->ls_start = TIME_TV2USEC(*tv); 19 Line660. Dereferencing of "tv" which can be null Dereferencing of "tv" which can be null 告警处理帮助           info->admin_start = TIME_TV2USEC(tv_admin_old);           info->offset = info->ls_start - info->admin_start;             /* 基于新的admin start设置了偏移,所以admin_start也重新设置一下, 否则需要计算出admin原来偏移的间 */           ret = ls_time_offset_info_set(g_ls_time_lsid, info);             if (sem_ret == 0) {               (void)ls_time_sem_post_ls(g_ls_time_lsid);           }       } else {
05-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值