I am struggling with multithreading concepts here.
There are two threads that access a shared struct. Idea is to have ThreadTwo
acquire the lock first and sets data
to true, and then ThreadOne
run...which goes to sleep if data
is set to true
, and wake up once signalled after data
being set to false
.
What I'm seeing happen: ThreadOne
goes to sleep, and after ThreadTwo
disables data
, both the threads seem to be in a deadlock state or rather they're stuck.
My understanding is: I unlock the mutex at the end of AccessShm(shmInfo, GET)
, and I believe pthread_cond_signal
requires to have lock already acquired because it unlocks before going to sleep, and once signalled from ThreadTwo
, ThreadOne
wakes up, acquires a lock, and attempts to acquire again inside AccessShm
but can't because it's already been acquired hence the hang?
typedef enum
{
SET,
GET
} Task;
typedef struct
{
volatile bool data;
pthread_mutex_t pMutex;
pthread_cond_t cv;
} ShmInfo;
bool AccessShm(ShmInfo *pShm, Task t, ...)
{
va_list args;
bool setValue = true;
bool retValue = true;
va_start(args, t);
pthread_mutex_lock(&pShm->pMutex);
switch (t)
{
case SET:
setValue = va_arg(args, bool);
pShm->data = setValue;
if (setValue == false)
{
pthread_cond_signal(&pShm->cv); // wake up only when pShm->data is disabled
}
break;
case GET:
retValue = pShm->data;
break;
default:
break;
}
pthread_mutex_unlock(&pShm->pMutex);
return retValue;
}
void ThreadOne(void *arg)
{
ShmInfo *shmInfo = (ShmInfo *) arg;
while(1)
{
while(AccessShm(shmInfo, GET) == true)
{
pthread_cond_wait(&shmInfo->cv, &shmInfo->pMutex);
}
// ...
}
}
void ThreadTwo(void *arg)
{
ShmInfo *shmInfo = (ShmInfo *) arg;
// ...
AccessShm(shmInfo, SET, true);
// some work/delay
AccessShm(shmInfo, SET, false);
}
CodePudding user response:
Could it be because you're not calling va_end()
(which is required) in AccessShm()
?
Apparently not.
The structure of your use of the mutex and condition variable is a little unusual. Typically, the mutex is locked when pthread_cond_wait()
is called in order to ensure determinism.
I suggest moving the locking/unlocking of the mutex out of AccessShm()
and into both ThreadOne()
and ThreadTwo()
. The call to pthread_cond_signal()
can be left in AccessShm()
on the assumption that the mutex is locked, which you can verify via a call to assert(pthread_mutex_trylock(&pShm->pMutex))
at the beginning of that function's body.
CodePudding user response:
You are not locking the mutex associated with your condition variable before calling pthread_cond_wait()
.
You must only call pthread_cond_wait()
with the associated mutex locked.
Per the POSIX pthread_cond_wait()
documentation(bolding mine):
The
pthread_cond_timedwait()
andpthread_cond_wait()
functions shall block on a condition variable. The application shall ensure that these functions are called withmutex
locked by the calling thread; otherwise, an error (for PTHREAD_MUTEX_ERRORCHECK and robust mutexes) or undefined behavior (for other mutexes) results....