使用和不使用条件变量的两个线程有​​什么区别?

What is the difference between the two threads using and not using conditional variables?

我写了一段简单的代码来学习pthread_cond_signal()和pthread_cond_wait()。我在代码1中使用了pthread_cond_signal()和pthread_cond_wait(),但是在代码2中我没有使用pthread_cond_signal()和pthread_cond_wait(),为什么我认为code 1和code 2有区别吗?我不明白条件变量吗?

typedef void VOID;
typedef unsigned int UINT32;

代码 1:

extern VOID TriggerStoreCond(VOID)
{
    static INT32 i = 0;
    pthread_mutex_lock(&StoreInfoMutex);
    ConfirmChanged = i++;   
    pthread_cond_signal(&StoreCond);
    pthread_mutex_unlock(&StoreInfoMutex);
}
static VOID *StoreInfoFunction(VOID *arg)
{
    INT32 *pComfirmChanged = (INT32 *)arg;
    INT32 temp = *pComfirmChanged;
    
    while (1)  
    {
        pthread_mutex_lock(&StoreInfoMutex);
        while (temp == *pComfirmChanged) 
        {
            pthread_cond_wait(&StoreCond, &StoreInfoMutex);
        }
        pthread_mutex_unlock(&StoreInfoMutex);
        printf("store info to sqlite3!,*pComfirmChanged = %d\n", *pComfirmChanged);
        ///////////////////////////////////////////////////////////
        //here, do my job.
        ///////////////////////////////////////////////////////////
        temp = *pComfirmChanged;
    }
    pthread_exit((void*)"exit StoreInfoFunction!"); 
}

extern VOID StoreInfo(VOID)
{
    pthread_t storeInfoThread;
    INT32 ret = 0;
    
    ret = pthread_create(&storeInfoThread, NULL, StoreInfoFunction, (VOID *)&ConfirmChanged);
    if (ret != 0)
    {
        printf("(%s) failed to create a pthread, return error code : %d.\n", __FUNCTION__, ret);
        exit(-1);
    }
}

代码 2:

extern VOID TriggerStoreCond(VOID)
{
    static INT32 i = 0;
    ConfirmChanged = i++;   

}
static VOID *StoreInfoFunction(VOID *arg)
{
    INT32 *pComfirmChanged = (INT32 *)arg;
    INT32 temp = *pComfirmChanged;
    
    while (1)  
    {
        while (temp == *pComfirmChanged) 
        {
            sleep(1);
        }
        printf("store info to sqlite3!,*pComfirmChanged = %d\n", *pComfirmChanged);
        ///////////////////////////////////////////////////////////
        //here, do my job.
        ///////////////////////////////////////////////////////////
        temp = *pComfirmChanged;
    }
    pthread_exit((void*)"exit StoreInfoFunction!"); 
}

extern VOID StoreInfo(VOID)
{
    pthread_t storeInfoThread;
    INT32 ret = 0;
    
    ret = pthread_create(&storeInfoThread, NULL, StoreInfoFunction, (VOID *)&ConfirmChanged);
    if (ret != 0)
    {
        printf("(%s) failed to create a pthread, return error code : %d.\n", __FUNCTION__, ret);
        exit(-1);
    }
}

主要区别在于,在您的第一个代码示例中,您等待 信号。如果信号到达,线程将 'immediately' 继续。

在您的第二个示例中,您正在轮询一个全局(状态)变量并休眠一段特定的时间。如果在此期间状态发生变化,您会注意到在您醒来后 发生了变化。所以,你会有一定的时间延迟。

另一个区别是,第一个代码是同步的,第二个不是。这可能会产生副作用,如果许多线程不断修改状态变量,则您的线程必须在正确的时刻唤醒,此时状态已经设置好,它可以继续,否则它将继续休眠(机会否则运气将是主导因素)。

I wrote a simple piece of code to learn pthread_cond_signal() and pthread_cond_wait(). I used pthread_cond_signal() and pthread_cond_wait() in code 1, but I didn't use pthread_cond_signal() and pthread_cond_wait() in code 2. Why do I think there is no difference between code 1 and code 2?

我无法说出你的思维过程。显然,通过比较两个代码,可以看出差异。

Do I not understand conditional variables?

如果您假设这两个代码尽管存在差异,但等同,那么不,您不了解条件变量。条件变量为一个线程提供了一种暂停操作不确定时间的方法,直到另一个线程表明它可能值得继续,而 sleep() 产生(或多或少)固定时间暂停。

此外,需要将 CV 与互斥体一起使用是有目的且重要的。人们通常使用互斥锁来保护共享对象,等待线程将通过它来确定是否继续,并且互斥锁在等待开始时自动解锁并在等待结束前再次锁定这一事实允许正确同步对这些对象的访问,而无需数据竞争或时序漏洞。这不是执行暂停方面,而是条件变量的真正关键。

但是,恐怕很难用您的示例来证明这一点,因为该示例有一个严重的设计缺陷:它继续进行的条件是某些共享对象的值与线程先前观察到的值发生变化,但这是一个依赖于时间的标准,本质上容易受到时间问题的影响。

假设某个其他线程想要触发 StoreInfoFunction 线程以继续“执行我的工作”部分。它有什么作用?嗯,看起来它会在 *pComfirmChanged 中设置一个新值,但是如果 StoreInfoFunction 线程尚未到达它读取该对象的值以分配给 temp 的部分怎么办? ?或者如果第二个线程更新 *pComfirmChangedStoreInfoFunction 线程是 运行 “做我的工作”部分,然后再将新值读入 temp 怎么办?或者,如果第二个线程在 StoreInfoFunction 线程休眠时更新 *pComfirmChanged 两次或更多次怎么办?

即使使用适当的互斥保护来防止数据竞争,如果没有 CV 等待的互斥相关语义,您将无法编写可靠地正确处理所有此类情况的代码。