我正在寻找一种高效的系统,该系统具有一系列按层次结构组织的读/写锁,以管理对按层次结构组织的资源的访问。如果一个子树被锁定用于写,那么在整个子树中不应该能够获得其他锁,直到它被释放;类似地,子树中的写锁应该防止父树中的锁定。
以下是我正在考虑的想法:
我准备走最后一条路,但令我惊讶的是没有找到任何现有的库可以更好地解决这个问题。那么:
- 我是否错过了一些明显的解决方案?
- 或者这个问题特别难以正确解决?
I'm looking for en efficient system to have a series of read/write locks organized hierarchically to manage access to hierarchically organized resources. If a subtree is locked for write, then no other lock should be able to be obtained in the whole subtree until it is released; similarly, a write lock in a subtree should prevent locking in a parent.
Here are the ideas I was contemplating:
-
Use the Apache Commons Transaction. Unforunately, the project hasn't been updated since March 2008 and has unofficially been terminated. Some API docs seemed to indicate that the version to come (1.3 or 2.0) would include some kind of hierarchical locking, but the sources are nowhere to be found and it seems we can't access their SVN repository any more.
-
Use a series of ReentrantReadWriteLock
s, which I would organize hierarchically. I'm no concurrency expert, and I'm a bit afraid to do that on my own. Preliminary thoughts seemed to indicate that even before I can try to lock a subtree, I'd have to use an outer lock on the whole structure managing the ReentrantReadWriteLock
s itself — so that even for releasing a lock I'd have to use the outer lock…
-
Use classes from java.util.concurrent
and java.util.concurrent.atomic
to implement my hierarchical lock in a more efficient way than I could do with a series of ReentrantReadWriteLock
s.
I'm ready to go down that last road, but I was surprised not to find any exiting library that would solve this problem better. So:
- Have I missed some obvious solution?
- Or is this problem just especially hard to solve properly?
发布评论
评论(2)
我不知道我是否理解你的问题,正如你所说,当你锁定子树进行写入时,整个结构都被锁定。
因此,一种简单的解决方案是为整个结构设置一个 RW 锁。
顺便说一句,
java.util.concurrent.atomic
不会比 RW 锁树对您有更多帮助。如果您希望能够独立锁定同级,您可以采用第二种解决方案(锁树,其中每个节点都有对其父节点的引用)。
锁定一个节点将使用其写锁来锁定它,并使用读锁来锁定每个父节点。
当子级被锁定时,父级不能被锁定,因为您无法获取其写锁,因为锁定子级已经获取了读锁。
仅当没有其他线程对任何父线程进行写锁定时才允许锁定子线程。
上面描述的锁是排他锁。
(读写锁的另一个名称是共享独占锁)
要添加共享锁,每个节点还需要一个原子整数,表示:
如果为正,则为间接写锁定子级的数量;如果为负数,则表示节点被读锁定的次数。
此外,节点及其父节点将被读锁定,以避免在父节点上获取新的写锁。
伪代码:
如果无法获取任何锁定,则解锁已锁定的内容并稍后重试(可以使用全局条件变量、超时等来实现此目的)。
编辑:添加了读锁定/写锁定树的代码
I don't know if I understood well your question, as you say that when you lock a subtree for write, the whole structure is locked.
So, the simple solution is to have one RW lock for the whole structure.
By the way,
java.util.concurrent.atomic
won't help you more than a tree of RW locks.If you want to be able locking siblings independly, you may go with the second solution (a tree of locks where each node has a reference to its parent).
Locking a node would be locking it using its write lock and locking every parent using read locks.
A parent cannot be locked while a child is, because you cannot acquire its write lock as locking a child already acquired the read lock.
Locking a child is only permitted if no other thread has write-locked any parent.
The lock described above is an exclusive lock.
(another name for read-write locks is shared-exclusive locks)
To add shared locks, each node also needs an atomic integer indicating:
if it's positive, the number of indirect write-locked children; if it's negative the number of times the node has been read-locked.
Also, the node and its parents will be read locked to avoid new write locks being acquired on parents.
The pseudo-code:
If any lock couldn't be acquired, then you unlock what you have locked and retry later (you can use a global condition variable, a timeout, etc to achieve this).
EDIT: added code to read-lock/write-lock a tree
我将采用您自己的解决方案并采用 Apache Apache Commons Transaction Algorithm 作为起点。
您可以使用 ReentrantReadWriteLock,尽管通常这种锁更适合一个生产者 - 许多读者的情况,这可能不是您想要的。看起来你的锁更像是一个常规的可重入互斥锁。
I will go for your own solution and take the algorithm given by Apache Apache Commons Transaction Algorithm as starting point.
You can use a ReentrantReadWriteLock although usually this lock fits better the pattern of one producer-many readers case which may not be what you are looking for. It seems your lock is more like a regular reentrant mutex lock.