Reputation: 187
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?
typedef void VOID;
typedef unsigned int UINT32;
code 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);
}
}
code 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);
}
}
Upvotes: 0
Views: 61
Reputation: 181149
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?
I cannot speak to your thought process. Clearly, there are differences evident by comparison of the two codes.
Do I not understand conditional variables?
If you are supposing that the two codes, despite their differences, are equivalent, then no, you do not understand condition variables. Condition variables provide a means for one thread to suspend operation for an indeterminate time, until another thread suggests that it might be worthwhile to proceed, whereas sleep()
produces a (more or less) fixed time suspension.
Moreover, the required usage of a CV together with a mutex is purposeful and significant. One generally uses a mutex that protects the shared objects by which the waiting thread will determine whether to proceed, and the fact that the mutex is unlocked automatically when the wait begins and locked again before the wait ends permits proper synchronization of access to those objects without data races or timing vulnerabilities. This, not execution suspension aspect, is the true key to condition variables.
I am afraid, however, that that is difficult to demonstrate with your example, because the example has a critical design flaw: its condition for proceeding is that the value of some shared object changes from the value the thread previously observed, but that's a timing-dependent criterion, inherently vulnerable to timing problems.
Suppose that some other thread wants to trigger the StoreInfoFunction
thread to proceed to the "do my job" part. What does it do? Well, it looks like it would set a new value in *pComfirmChanged
, but what if the StoreInfoFunction
thread has not yet reached the part where it reads the value of that object to assign to temp
? Or what if the second thread updates *pComfirmChanged
while the StoreInfoFunction
thread is running the "do my job" part, before reading a new value into temp
? Or what if the second thread updates *pComfirmChanged
twice or more while the StoreInfoFunction
thread is sleeping?
Even with proper mutex protection to prevent data races, you will have trouble writing code that is reliable in handling all such cases correctly without the mutex-related semantics of a CV wait.
Upvotes: 3
Reputation: 5868
The main difference is, that in your first code example you wait for a signal. If a signal arrives, the thread will 'immediately' continue.
In your second example you're polling a global (state) variable and go to sleep for a specific amount of time. If in the meantime the state changes, you will notice that change after you've woken up. So, you'll have a certain time delay.
Another difference is, that the first code is synchronized, the second is not. That could have the side effect, that if many threads are continously modifying the state variable, your thread would have to wake up at the right moment, where the state is such set, that it can continue, otherwise it will continue to sleep (chance or luck would be the dominant factor).
Upvotes: 1