这是(大致)我所拥有的:
class A
{
public bool IsInUpdate = false;
public void Update()
{
IsInUpdate = true;
//(...do stuff...)
IsInUpdate = false;
}
}
class B
{
A a_inst;
System.Threading.Thread physicsThread = null;
void Draw()
{
physicsThread = new System.Threading.Thread(a_inst.Update);
physicsThread.Start();
}
void Update()
{
while(physicsThread.IsAlive)
{
// Right here there can be cases where physicsThread.IsAlive is true but IsInUpdate is false, how does that happen?
}
(...do stuff...)
}
}
问题在于代码的注释。基本上物理线程实例说它还活着,但它调用的函数显然已经完成调用(可以看出bool设置为false)。
为什么会这样?我想要做的就是确保在执行A类的线程更新功能之前,B类中的更新函数不会执行...
答案 0 :(得分:6)
由于IsInUpdate
只是一个公共字段(而非volatile
),因此 没有 保证您所看到的内容;关于你所看到的内容的正常合理规则仅适用于单个线程,并且你没有保护任何这些数据。 start 条件还有一个边缘情况,但我个人会使用lock
(如果你需要等待它完成),或者Interlocked
如果你只是需要知道它是否有效。
例如:
class A
{
private readonly object syncLock = new object();
public object SyncLock { get { return syncLock; } }
public void Update()
{
lock(SyncLock)
{
//(...do stuff...)
}
}
}
和
void Update()
{
lock(a_inst.SyncLock)
{
(...do stuff...)
}
}
通过上述内容,您可以保证任何时候只有一个线程可以拥有锁定,因此如果您“执行某些操作”,您知道它还没有运行其他更新()。如果您需要等待等,还有针对锁定的Wait()
/ Pulse()
方法,或者您可以使用ManualResetEvent
/ AutoResetEvent
等门。
lock
之类的东西也确保线程之间存在正确的内存障碍,因此您可以看到正确的数据。
答案 1 :(得分:2)
当尚未调用Update
函数时,可能会发生这种情况。仅仅因为你在线程上调用Start
并不意味着它会立即执行它的主要功能。我不是100%确定是否有一个轻微的机会窗口,其中线程仍处于活动状态,但主要功能已完成执行。
基本上,您希望查看ManualResetEvent
或AutoResetEvent
以表示您的线程已完成工作。或者,您可以在Update()
完成后B
可以订阅的事件可能已经足够好了。像这样:
class A
{
public event EventHandler UpdateFinished;
public void Update()
{
... do work
var handler = UpdateFinished;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
class B
{
public void Draw()
{
a_inst.UpdateFinished += HandleUpdateFinished;
... start your thread
}
private void HandleUpdateFinished(object sender, EventArgs e)
{
... do whatever
}
}