消除僵局
我目前正在(尝试)编写一个小游戏。我有一个小的设计/死锁问题。
当我按下按钮时,会打开一个新的 Intent,并且 surfaceDestroyed 设置一个布尔值来设置线程休眠。 当我返回时,线程收到通知信号。
这在大约 90% 的情况下有效(当我使用 eclipse 调试时为 100%)。
我相信死锁发生在线程的run函数中(两个synchronized)。问题是,wait() 需要线程的同步,而 ondraw() 需要表面持有者上的锁。
我已经玩了一下,但所有其他组合都会让一切变得更糟,我不知道如何解决这个问题。所以请帮忙:)
主题:
class BattleEarthThread extends Thread {
private SurfaceHolder _surfaceHolder;
private BattleEarthView _battleEarthView;
private boolean _run = false;
private boolean _suspended = false;
public SurfaceHolder getSurfaceHolder() {
return _surfaceHolder;
}
public BattleEarthThread(SurfaceHolder surfaceHolder, BattleEarthView panel) {
_surfaceHolder = surfaceHolder;
_battleEarthView = panel;
}
public void setRunning(boolean run) {
_run = run;
}
public void setSuspend(boolean suspend) {
_suspended = suspend;
}
public boolean getSuspended() {
return _run;
}
public boolean getRunning() {
return _run;
}
@Override
public void start() {
super.start();
_run = true;
}
@Override
public void run() {
Canvas c;
while (_run) {
c = null;
try {
synchronized(this)
{
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
if(_suspended)
this.wait();
else {
_battleEarthView.onDraw(c);
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
i'm currently (trying) to program a little game. And i have a small design/deadlock issue.
When i press a button, a new Intent opens and surfaceDestroyed sets a boolean to set the thread sleeping.
When i return the thread gets a notify signal.
This works in about 90% of the time (and 100% when i debug with eclipse).
I believe the deadlock takes place in the run function of the thread (two synchronized). The problem is, wait() needs a synchronized of the thread and ondraw() needs the lock on the surfaceholder.
I played already around a bit, but all other combinations makes everything worse, and i dont know how to solve this. So please help :)
The Thread:
class BattleEarthThread extends Thread {
private SurfaceHolder _surfaceHolder;
private BattleEarthView _battleEarthView;
private boolean _run = false;
private boolean _suspended = false;
public SurfaceHolder getSurfaceHolder() {
return _surfaceHolder;
}
public BattleEarthThread(SurfaceHolder surfaceHolder, BattleEarthView panel) {
_surfaceHolder = surfaceHolder;
_battleEarthView = panel;
}
public void setRunning(boolean run) {
_run = run;
}
public void setSuspend(boolean suspend) {
_suspended = suspend;
}
public boolean getSuspended() {
return _run;
}
public boolean getRunning() {
return _run;
}
@Override
public void start() {
super.start();
_run = true;
}
@Override
public void run() {
Canvas c;
while (_run) {
c = null;
try {
synchronized(this)
{
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
if(_suspended)
this.wait();
else {
_battleEarthView.onDraw(c);
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这就是问题所在:
您取出了两把锁 -
this
和_surfaceHolder
。然后,您通过调用wait
释放this
上的锁...但您仍然拥有_surfaceHolder
的锁>。现在假设另一个线程在同一个对象上执行相同的代码。它设法获取
this
的锁,因为目前没有其他线程拥有它......但在尝试获取_surfaceHolder
时它会阻塞,因为等待线程拥有它。此时,您已经被塞满了:
this
上的锁,这是它无法做到的。所以基本上你有两个线程,每个线程都拥有一个锁,并且正在等待不可能发生的事情发生。这与正常的死锁(每个线程拥有一个锁并等待另一个线程的锁)不同,但也非常接近。
寓意:不要在当前“拥有”比要调用
wait()
的监视器更多的线程上调用wait()
。This is the problem:
You're taking out two locks -
this
and_surfaceHolder
. You're then releasing the lock onthis
by callingwait
... but you still own the lock for_surfaceHolder
.Now suppose another thread executes the same code on the same object. It manages to acquire the lock for
this
, because nothing else owns it at the moment... but it blocks when trying to acquire_surfaceHolder
, because the waiting thread owns it.At this point, you're stuffed:
this
before continuing, which it won't be able toSo basically you've got two threads, each of which owns one lock and is waiting for something impossible to happen. It's not quite the normal deadlock (where each thread owns one lock and is waiting for the other's) but it's pretty close.
Moral: don't call
wait()
on a thread which currently "owns" more monitors than the one it's about to callwait()
on.