结合使用语句和锁
本文关键字:语句 结合 | 更新日期: 2023-09-27 18:10:07
下面的代码是不安全的(至少我认为是这样):
using (SQLiteConnection connection = new SQLiteConnection("path")) {
MyTableCreationHelper.CreateTable(connection, "tableName"));
}
问题是,如果另一个线程试图在到同一路径的不同连接上创建表,数据库将被锁定,因此将抛出异常。为了防止这种情况发生,我可以这样做:
object lockObject = myLockHelper.GetUniqueObjectForLocking("path"); //does what it claims to do; implementation not shown
lock (lockObject) {
using (SQLiteConnection connection = new SQLiteConnection("path")) {
MyTableCreationHelper.CreateTable(connection, "tableName"));
}
}
现在代码是安全的,但也更笨拙,因为我每次都必须将using包装在锁中。我的问题是,有没有办法把使用和锁结合起来,让它不那么笨重?
理想情况下,它将以一种不依赖于我们的内部操作涉及SQLiteConnection的事实的方式完成。换句话说,为SQLiteConnection编写一个锁定包装器不是一个理想的解决方案,因为如果下次我的锁不涉及SQLite,那么问题将再次出现。
您可以有一个通用的包装器类,它接受一个IDisposable参数,以及相同的字符串参数,该参数执行锁定并在其上使用using
。(未测试的代码):
public class LockWrapper<T>:IDisposable
where T:IDisposable
{
T obj;
object lockObject ;
public LockWrapper(T obj, string Name)
:this(()=>obj, Name)
{
}
public LockWrapper(Func<T> objcreator, string Name)
{
lockObject = myLockHelper.GetUniqueObjectForLocking("path");
Monitor.Enter(lockObject);
this.obj = objcreator();
}
public T Object{get{return obj;}}
public void Dispose()
{
try
{
obj.Dispose();
}
finally
{
Monitor.Exit(lockObject);
}
}
}
//helper inside a static class
public static LockWrapper<T> StartLock(this T obj, string LockName)
where T:IDisposable
{
return new LockWrapper<T>(obj, LockName);
}
这是直接输入到SO中,所以我甚至不知道我是否犯了语法错误,但思想是一样的,包装器对象负责锁定。
调用应该是这样的:
using(var lck = new SQLiteConnection("path").StartLock("path"))
MyTableCreationHelper.CreateTable(lck.Object, "tableName"));
另一种方法是一直使用lambda并使用像
这样的东西 public static void RunLocked<T>(Func<T> objCreator, Action<T> run, string LockName)
where T:IDisposable
{
lock(getlockobject(LockName))
{
using(var obj = objCreator())
{
run(obj);
}
}
}
但是调用就不那么直观了:
RunLocked(()=> new SQLiteConnection("path"),
connection => MyTableCreationHelper.CreateTable(connection , "tableName"),
"path");