【发布时间】:2019-02-27 05:20:59
【问题描述】:
我正在用 C 语言实现信号量的简单实现,当我的实现工作(作为二进制信号量)时,我对其有效性有疑问。
我的担忧源于我对等待函数的定义:
void Wait(int semid) {
char *shmPtr;
shmPtr = shmat(semid, NULL, 0);
if(shmPtr == (void *) -1){
printf("Could not attach to semaphore...\n");
exit(1);
}
//Wait for the value in shared memory to
//equal 0, then set it equal to 1,
//detach and return
while( (*shmPtr) != 0);
(*shmPtr) = 1;
if(shmdt(shmPtr) < 0) {
printf("Cannot detach from semaphore...");
}
return;
}
我的问题在于 while( (*shmPtr) != 0) 环形。假设我们有 2 个进程正在等待。第三个过程将信号量的值更改为等于 0(忽略这是信号量的二进制实现这一事实)。
我担心的是,如果进程 1 评估 while 循环的条件为假,然后 CPU 上下文在将信号量值设置为 1 之前切换到进程 2,则两个进程都会进入临界区。
有没有更好的方法来实现等待功能?我见过很多人使用 pthread_cond_wait,但它使用了互斥体,这基本上违背了信号量实现的目的。
谢谢
编辑:添加*在 C 中的 TestAndSet 实现以在 cmets 中引用
#define LOCKED 1
int TestAndSet(int* lockPtr) {
int oldValue;
oldValue = *lockPtr;
*lockPtr = LOCKED;
// -- End of atomic segment --
return oldValue;
}
【问题讨论】:
-
这称为竞争条件。您需要一些您没有的原子测试和设置操作之王。否则,两个进程都可以将其视为 0,然后它们都将尝试将其更改为 1,每个进程都认为自己是第一个这样做的。基本上,您无法知道它在将其视为零和将其设置为一之间没有改变。
-
正是我担心的。这种实现似乎可以作为二进制信号量正常工作,因为两个进程不会同时等待。我不知道在同一个语句中检查值和增加值的方法,你有什么想法吗?
-
你没有实现信号量。您使用一个(借助一些外部库)
-
在某个时候有人实现了它。了解你的代码在最低层次上做了什么会让你成为一个更好的程序员,而不是仅仅接受某件事有效并继续前进。
-
while( (*shmPtr) != 0);您的编译器有权完全优化此循环。