请稍侯

pthread_cond_timedwait的使用问题

2015年 10月27日
更多

在信息接收,以及多线程处理时,经常需要用到信号量进行同步操作.近来在信号量上遇到了一个蠢问题,但还是有一些东西可以记一下.

信号量的使用上,是与mutex(互斥量一起使用的).其作用是防止多方占用资源.一般是先Lock再cond_timedwait,之后再等待signal或是pthread_cond_broadcast

pthread_condattr_t  condattr;

pthread_condattr_init(&condattr);
pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
pthread_cond_init(&(tThreadCond),&condattr);
pthread_mutex_init(&tThreadMutex,NULL);

s32Ret = pthread_mutex_lock(&tThreadMutex);
if(s32Ret != 0)
{
    HAL_TRACE(HAL_LOG_LEVEL_ERROR, "Mutex lock error!!!");
}
s32Ret = pthread_cond_timedwait(&tThreadCond,&tThreadMutex, &tv);
if(s32Ret == ETIMEDOUT)
{
}
else if(s32Ret != 0)
{
}
else
{
    clock_gettime(CLOCK_MONOTONIC, &tv);
    tv.tv_sec += 3;
}
s32Ret = pthread_mutex_unlock(&tThreadMutex);  

其实timedwait有两种方式,一种是绝对时间,以date来判断,但是在极端情况下可能会因系统时间更改影响到运行(虽然可能性小,但是会出现.).所以一般以相对时间来.CLOCK_MONOTONIC.这个是以系统运行时间来判断的.就不会遇到上面的问题了

pthread_cond_timedwait会有三种情况下退出等待,一个是超时,一个是出错,一个是收到了信号量.信号的发送:

void ThreadSignal(TagThreadInfo *threadInfo)
{
    s32 s32Ret = -1;
    s32Ret = pthread_mutex_lock( &threadInfo->tThreadMutex); 
    if(s32Ret != SUCCESS)
    {
        return; 
    }
    s32Ret = pthread_cond_broadcast(&threadInfo->tThreadCond);
    //s32Ret = pthread_cond_signal(&threadInfo->tThreadCond);
    s32Ret = pthread_mutex_unlock(&threadInfo->tThreadMutex); 
    if(s32Ret != SUCCESS) 
    {
        return;
    }
}

用broadcast更好.

pthread_cond_timedwait调用后,是可以在发信号函数再次Lock.因为pthread_cond_timedwait这个函数在进行后,会先unlock操作,再返回后,又会有个unlock的操作.所以理论上可以在一个线程进行等待后,另一个线程也进入等待操作.而退出等待时,则是随机.所以除非有明显的优势,还是不要避免这种情况下.

在收到信号后,timedwait就会退出等待.这里的话,在使用过程中,lock以及unlock的位置也很重要的.因为用到了Lock,在一个线程进行了lock状态时,在没有unlock情况下,是不能允许有其他的线程进行lock的.

另,timedwait是可能错过信号的,比如你读写各有一个线程.而写函数中,是先write后lock再进行等待的话,可能在刚写完,写函数还没有Lock的情况下,read线程就有数据上来并读出,这时,read函数先入了lock,发送了信号量一套完整操作,而这时write才进入lock,等待的话,会错过信号的接收。写线程应该在write前就先lock住,这样,即使在写线程还没有进行到调用timedwait,读线程因为无法lock而卡住 。只有在写线程调用了pthread_cond_timedwait,释放了lock,读线程才能发出信号。同理,unlock一样的重要。

最后,再来讲一下遇到的蠢问题。在一切正常的情况下,我遇到了刚调用pthread_cond_timedwait立即返回ETIMEDOUT的现象。本来是以为时间参数错误,但是确认后发现没有问题。甚至怀疑过,是不是系统硬件只允许一定数量的timedwait,因为其他的运行很正常。最后,发现,其原因是,在初始化这个参数后,又进行了清0的操作。即mutex,cond的变量为全0.这时,函数lock不会报错,unlock也不会报错。但是timedwait会直接返回超时(我个人觉得这个错误码不太正确)。这个问题还是找了一两天。在这里记录下。