我对经典的有界缓冲问题做了一个修改。
这是一个很大的不同,在我需要知道的线程安全的道路上有一个小的技术障碍(而不是无休止地测试可能永远不会发生的标准化)
我真的不认为我需要解释以下代码示例的评估情况
if(buffer1.BufferNotFull)
{
buffer1.Lock();
buffer1.AddValueAtIndex(value, index);
buffer1.Unlock();
}
基本上我的buffer1有一个简单的条件变量(更新和全部),让我知道它是否已满,然后我获取一个锁,做魔术并释放锁。
但是我可以简单地假设评估条件“缓冲区不完整”不能与另一个线程交错,只是在我的缓冲区中写入LAST插槽吗?
(缓冲区实际上是一个值数组,-1表示空,不要问为什么^ _ ^)
简而言之:是评估
if(buffer1.BufferNotFull)
线程安全与正文代码获取锁
修改
这是我现在用于整个系统的系统。我希望它有助于展示我的设计。考虑到我将这个设计纯粹用于这些基本同步机制的学习目的。
访问缓冲区的线程的控制流程
读输入流(无需同步)
ATTEMPT:
ATTEMPT:
ATTEMPT:
ATTEMPT:
控制各个线程操作的流程
获取锁定 检查条件变量 如果是,则进行写/读操作 如果不是,请等待notfiy 解锁
我将构建并测试实现的最后一部分并进行编辑,以查看接受的答案是否真的能让我获得结果,但这可能需要一些时间
答案 0 :(得分:3)
通常,在上面的场景中,您必须首先获取锁定,然后测试条件是否为真:
buffer1.Lock();
try {
while( !buffer1.BufferNotFull ) {
buffer1.WaitOnConditionVariable();
}
buffer1.AddElement(...);
} finally {
buffer1.Unlock();
}
操作的任何其他顺序都会带来“检查时间/使用时间”竞争条件的风险:考虑当前线程在使用{{1}检查状态后立即被抢占的情况但在抓住锁之前。如果新线程将新元素添加到缓冲区,则缓冲区的状态可能会再次变为“满”。当原始线程恢复时,它会在尝试添加自己的新元素时触发“缓冲区满”异常(或其他),即使它正确地检查(从它自己的角度来看)。
编辑条件变量将在“等待”操作期间实际进入休眠状态之前释放锁定。这是以原子方式完成的,即线程将在释放锁定时“在同一时刻”进入休眠状态。当某个其他线程通知该变量时,它会在调用“WaitOnConditionVariable”之后重新获取锁之前重新获取该锁。
从缓冲区中删除元素的代码可能如下所示:
BufferNotFull
或者,让它看起来像Java:
buffer1.Lock();
try {
if( !buffer.IsEmpty ) {
... remove element ...
BufferNotFull = true;
NotifyConditionVariable();
}
} finally {
buffer1.Unlock();
}
添加元素:
Object monitor = new Object();
boolean full = false;
boolean empty = true;
删除元素:
synchronized( monitor ) {
while( full ) {
monitor.wait();
}
... add element ...
... maybe set full ...
empty = false;
monitor.notifyAll();
}