开发者

kill the deadlock

开发者 https://www.devze.com 2023-04-13 01:12 出处:网络
i\'m currently (trying) to program a little game. 开发者_JAVA技巧And i have a small design/deadlock issue.

i'm currently (trying) to program a little game. 开发者_JAVA技巧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);
                }
            }
        }
    }
}


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号