消除僵局

发布于 2024-12-10 12:40:32 字数 1977 浏览 0 评论 0原文

我目前正在(尝试)编写一个小游戏。我有一个小的设计/死锁问题。

当我按下按钮时,会打开一个新的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夏の忆 2024-12-17 12:40:32

这就是问题所在:

synchronized(this) {
    c = _surfaceHolder.lockCanvas(null);
    synchronized (_surfaceHolder) {

        if(_suspended)
            this.wait();

        else {
            _battleEarthView.onDraw(c);
        }
    }
}

您取出了两把锁 - this_surfaceHolder。然后,您通过调用 wait释放 this 上的锁...但您仍然拥有 _surfaceHolder 的锁>。

现在假设另一个线程在同一个对象上执行相同的代码。它设法获取 this 的锁,因为目前没有其他线程拥有它......但在尝试获取 _surfaceHolder 时它会阻塞,因为等待线程拥有它。

此时,您已经被塞满了:

  • 没有线程可以获取正在等待的对象上的锁,因为第二个线程拥有它
  • 即使另一个线程可以脉冲该锁,等待线程仍然需要在继续之前重新获取 this 上的锁,这是它无法做到的。

所以基本上你有两个线程,每个线程都拥有一个锁,并且正在等待不可能发生的事情发生。这与正常的死锁(每个线程拥有一个锁并等待另一个线程的锁)不同,但也非常接近。

寓意:不要在当前“拥有”比要调用 wait() 的监视器更多的线程上调用 wait()

This is the problem:

synchronized(this) {
    c = _surfaceHolder.lockCanvas(null);
    synchronized (_surfaceHolder) {

        if(_suspended)
            this.wait();

        else {
            _battleEarthView.onDraw(c);
        }
    }
}

You're taking out two locks - this and _surfaceHolder. You're then releasing the lock on this by calling wait... 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:

  • No thread can acquire the lock on the object being waited on, because the second thread owns it
  • Even if another thread could pulse that lock, the waiting thread would still need to reacquire the lock on this before continuing, which it won't be able to

So 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 call wait() on.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文