提出一个用于原子访问共享内存的包装器
Posted
技术标签:
【中文标题】提出一个用于原子访问共享内存的包装器【英文标题】:Coming up with a wrapper for atomically accessing shared memory 【发布时间】:2021-11-23 08:10:36 【问题描述】:我在这里纠结于多线程概念。
有两个线程访问一个共享结构。想法是先让ThreadTwo
获取锁并将data
设置为true,然后ThreadOne
运行...如果data
设置为true
,它将进入睡眠状态,并在@ 之后发出信号后唤醒987654326@ 被设置为false
。
我所看到的情况:ThreadOne
进入睡眠状态,在 ThreadTwo
禁用 data
之后,两个线程似乎都处于死锁状态,或者更确切地说它们被卡住了。
我的理解是:我在AccessShm(shmInfo, GET)
的末尾解锁了互斥锁,我相信pthread_cond_signal
需要已经获得锁,因为它在睡觉前解锁,并且曾经从ThreadTwo
发出信号,ThreadOne
唤醒,获取锁,并尝试在 AccessShm
内再次获取,但不能,因为它已经被获取,因此挂起?
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);
【问题讨论】:
【参考方案1】:可能是因为您没有在AccessShm()
中调用va_end()
(这是必需的)吗?
显然不是。
您使用互斥锁和条件变量的结构有点不寻常。通常,当调用pthread_cond_wait()
时,互斥锁会被锁定以确保确定性。
我建议将互斥锁的锁定/解锁从AccessShm()
移到ThreadOne()
和ThreadTwo()
中。假设互斥锁已锁定,对pthread_cond_signal()
的调用可以留在AccessShm()
中,您可以通过在该函数主体的开头调用assert(pthread_mutex_trylock(&pShm->pMutex))
来验证这一点。
【讨论】:
是的,这是我想念的东西,但肯定不是答案。你不认为它归结为导致它的锁定流吗?我不完全确定,但试图完全理解...... 这个包装器的想法是原子地访问变量,而不必在应用程序中手动调用互斥锁和解锁,以避免在错过锁定/解锁的情况下造成任何破坏。pthread_cond_signal
无论如何都必须在获得锁之后调用,所以将锁定机制留在包装器内不是更好吗?
@xyf 这是个好主意,除了在调用 pthread_cond_wait()
时应该锁定互斥锁,而且这是在包装器之外完成的——所以你不妨接受必要的东西。【参考方案2】:
在调用 pthread_cond_wait()
之前,您没有锁定与条件变量关联的互斥锁。
您必须只调用 pthread_cond_wait()
并锁定关联的互斥锁。
每the POSIX pthread_cond_wait()
documentation(加粗我的):
pthread_cond_timedwait()
和pthread_cond_wait()
函数应阻塞条件变量。 应用程序应确保调用这些函数时调用线程锁定mutex
;否则,将导致错误(对于 PTHREAD_MUTEX_ERRORCHECK 和健壮的互斥锁)或未定义的行为(对于其他互斥锁)。...
【讨论】:
对不起,互斥锁怎么和我的条件变量没有关联?应用中只有一个CV和一个MUTEX @xyf 您的ThreadOne
代码调用AccessShm
,它锁定然后解锁互斥体。然后在不持有互斥锁的情况下调用pthread_cond_wait
。这是非法的,原因有两个:1)标准是这样说的。 2) 如果对pthread_cond_signal
的调用发生在你调用pthread_mutex_unlock
之后但在你调用pthread_cond_wait
之前会发生什么?你会等待已经发生的事情,可能永远等待。
我明白你的意思,但是pthread_cond_signal
总是在AccessShm
内部获得锁之后调用
@xyf 你的代码不工作,标准说,“你必须做 X”,你在争论为什么你真的不需要做 X?!?
这不是争论,而是试图了解幕后事物的工作原理:) 你认为有可能有一个包装器来做我正在做的事情吗?以上是关于提出一个用于原子访问共享内存的包装器的主要内容,如果未能解决你的问题,请参考以下文章