我正在尝试处理非标准数据库的锁(即它本身不提供此功能)。我的程序具有对db的独占访问权限,但是有多个并发线程需要同步。
我之前使用的朴素实现是全局锁定,不允许并行访问单独的行(设计总是线程安全)。
要实现此功能,我的想法是使用一个公共哈希表来存储当前正在使用的所有行ID。需要同步访问此哈希表,通常是通过锁定它。
但是,如果我们发现我们要使用的行已经在使用,我们必须等待它被释放。这并非完全无足轻重,我的猜测是使用信号等待。
但是,我不确定如何做到这一点。你能想到一个实现这个功能的好方法吗?答案 0 :(得分:0)
您想要每行使用哈希表项是好的。作为此哈希表中的值,我将为此特定行存储一个锁。任何想要访问行的线程都会先检索(或创建)此哈希表中的相应锁。然后它将锁定并稍后释放它。
重要的是,对全局哈希表的所有访问都非常快。每行锁定一个对象可以解决这个问题,因为一旦您检索到锁定对象,无论您的操作持续多长时间,都可以立即解锁哈希表。
答案 1 :(得分:0)
我想出了这个天真的实现。
internal class LockingTest
{
private readonly Dictionary<string, ReaderWriterLockSlim> _Locks = new Dictionary<string, ReaderWriterLockSlim> ();
private void LockRow (string id)
{
ReaderWriterLockSlim slim;
for (; ; ) {
lock (_Locks) {
/*
* if row not in use, grab it
*/
if (!_Locks.TryGetValue (id, out slim)) {
slim = new ReaderWriterLockSlim (); // this can probably be replaced by a different, cheap signal class
slim.EnterWriteLock ();
_Locks.Add (id, slim);
return;
}
}
/*
* row is in use, wait until released, then try again
*/
slim.EnterWriteLock ();
}
}
private void UnlockRow (string id)
{
/*
* release and remove lock
*/
lock (_Locks) {
var slim = _Locks[id];
_Locks.Remove (id);
slim.ExitWriteLock ();
}
}
public void Test ()
{
var rnd = new Random ();
Action thread = () => {
for (; ; ) {
var id = rnd.NextDouble () < 0.5 ? "a" : "b";
Console.WriteLine (Thread.CurrentThread.Name + " waits for " + id);
LockRow (id);
Console.WriteLine (Thread.CurrentThread.Name + " locked " + id);
Thread.Sleep (rnd.Next (0, 100));
UnlockRow (id);
Console.WriteLine (Thread.CurrentThread.Name + " released " + id);
Thread.Sleep (rnd.Next (0, 100));
}
};
new Thread (() => thread ()) {
Name = "L1",
IsBackground = true
}.Start ();
new Thread (() => thread ()) {
Name = "L2",
IsBackground = true
}.Start ();
Thread.Sleep (1000);
}
输出
L1 waits for a L1 locked a L2 waits for b L2 locked b L2 released b L1 released a L1 waits for a L1 locked a L2 waits for a L1 released a L2 locked a L2 released a L1 waits for b L1 locked b L2 waits for b L1 released b L2 locked b L1 waits for a L1 locked a L2 released b L1 released a L1 waits for a L1 locked a L2 waits for a L1 released a L2 locked a L1 waits for b L1 locked b L1 released b L2 released a L1 waits for b L1 locked b L1 released b L2 waits for a L2 locked a L2 released a L1 waits for b L1 locked b L2 waits for a L2 locked a L2 released a L1 released b L1 waits for b L1 locked b L1 released b L2 waits for a L2 locked a L1 waits for a L2 released a L1 locked a L2 waits for b L2 locked b L1 released a L1 waits for b L2 released b L1 locked b L1 released b