设置系统时钟对sem_timedwait和pthread_cond_timedwait的影响

问题:当向前向后设置系统时间时,sem_timedwait和pthread_cond_timedwait会出现长时间堵塞或一直堵塞的情况;

分析:sem_timedwait() 是 通过传入未来的某个时钟实现超时等待信号量的获取,具体请参考 sem_timedwait(3),当调用sem_timedwait()后,因为系统实时时钟被修改,导致 sem_timedwait() 用于计算是否达到超时时钟的基准时钟向前大幅度偏移而阻塞,sem_timedwait()这个接口就是使用系统实时时钟计算超时的。同样的问题,这种情况下pthread_cond_timedwait就不能用绝对时钟计时方式。

解决方法:除了实时时钟之外,还有一个单调递增时钟,此时钟从某一时刻开始单调递增而不会被修改,详见 clock_gettime(3)。具体实现时,使用 clock_gettime(CLOCK_MONOTONIC, &ts) 获取单调递增时钟,再基于此时钟计算超时时间。所以在会修改系统实时时钟的应用中,需要谨慎使用 sem_timedwait(),而pthread_cond_timedwait时需要相当时间方式。

测试代码和修改代码参考如下:
 

#include <stdio.h>
#include<sys/time.h>
#include<unistd.h>
#include <time.h>

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>

#include <semaphore.h>
#include <pthread.h>
#include <signal.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <errno.h>
 
 
int set_system_time(char *dt)
{
    struct tm rtc_time;
    struct tm _tm;
    struct timeval tv;
    time_t timep;
    sscanf(dt, "%d-%d-%d %d:%d:%d", &rtc_time.tm_year,
        &rtc_time.tm_mon, &rtc_time.tm_mday,&rtc_time.tm_hour,
        &rtc_time.tm_min, &rtc_time.tm_sec);
    _tm.tm_sec = rtc_time.tm_sec;
    _tm.tm_min = rtc_time.tm_min;
    _tm.tm_hour = rtc_time.tm_hour;
    _tm.tm_mday = rtc_time.tm_mday;
    _tm.tm_mon = rtc_time.tm_mon - 1;
    _tm.tm_year = rtc_time.tm_year - 1900;
 
    timep = mktime(&_tm);
    tv.tv_sec = timep;
    tv.tv_usec = 0;
    if(settimeofday (&tv, (struct timezone *) 0) < 0)
    {
        printf("Set system datatime error!/n");
        return -1;
    }
    return 0;
}

void thread_sem_wait()
{
 int ret = -1;
 int timeoutms = 1000;
 struct timeval  ltv;
 struct timespec ts
 sem_t sem;
 sem_init(&sem,0,0);

  /* Fall back to RTC if realtime clock unavailable */
  gettimeofday(&ltv, 0);
  ts.tv_sec = ltv.tv_sec + timeoutms / 1000;
  ts.tv_nsec = (ltv.tv_usec + ((timeoutms % 1000) * 1000)) * 1000;
  while ((ret = sem_timedwait(&sem, &ts)) == -1 && errno == EINTR){
          continue;
      }
  
  printf("sem timewait:timeout\n")

}

void thread_cond_timedwait()
{
	pthread_cond_t cond;
	pthread_mutex_t mutex;
	struct timeval now;
	struct timespec waittime;
	int waitRet = 0;
	int msec = 100;

	
	mtos_task_sleep(1000);
	pthread_mutex_init(&mutex, NULL);
	
#if 1 /***relative time mode****/
    pthread_condattr_init(&cattr);
    pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC);
    pthread_cond_init(&cond, &cattr);
#else /**abstime mode***/
    pthread_cond_init(&cond, NULL);
#endif

	
#if 1  /***relative time mode****/
       clock_gettime(CLOCK_MONOTONIC, &waittime);
       waittime.tv_sec += 0;
       waittime.tv_nsec += (msec * 1000) * 1000; 
#else  /**abstime mode***/      
        gettimeofday(&now, NULL);
        waittime.tv_sec = now.tv_sec;
        waittime.tv_nsec = (now.tv_usec + msec * 1000) * 1000; 
#endif
	
	pthread_mutex_lock(&mutex);
	waitRet = -1;
	while(waitRet != ETIMEDOUT)
	{
	  waitRet = pthread_cond_timedwait(&cond, &mutex, &waittime);
	}
	
	pthread_mutex_unlock(&mutex);
	printf("sem timewait:timeout\n")
}



void msleep(unsigned int mSec) // milliseconds
{
   int ret = -1;
   struct timespec ts = {0};

    ts.tv_sec  =  mSec / 1000;
    ts.tv_nsec = (mSec % 1000) * 1000000;

    while (ret = nanosleep(&ts, &ts) == -1 && errno == EINTR){
	 	continue;
  }

}

void thread_function(sem_t *p_sem,u32 mSec)
{
set_system_time("2018-8-8 09:00:0");
msleep(50);
set_system_time("2017-8-8 09:00:0");
}

int my_sem_timedwait(sem_t *p_sem,u32 mSec)
{
  int ret = -1;
  u32 timeCnt = 0;
  timeCnt = 0;
  do{
     ret = sem_trywait(p_sem);
     if(ret != 0)
      {
        struct timespec timeParam = {0};
		    timeParam.tv_sec  = 0;
		    timeParam.tv_nsec = 1000000;
		    while (nanosleep(&timeParam, &timeParam) < 0 && errno == EINTR)
		    {
			   continue;		
		    }
        timeCnt ++;
        if(timeCnt >= mSec)
          {
           return -1;
          }
      }
     }while(ret != 0);

    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值