C# 使用语句和锁组合

C# 使用语句和锁组合,c#,multithreading,using,locks,C#,Multithreading,Using,Locks,以下代码是不安全的(或者至少我认为是): 问题是,如果另一个线程试图在同一路径的不同连接上创建表,数据库将被锁定,因此将引发异常。为了防止出现这种情况,我可以采取以下措施: object lockObject = myLockHelper.GetUniqueObjectForLocking("path"); //does what it claims to do; implementation not shown lock (lockObject) { using (SQLiteConnec

以下代码是不安全的(或者至少我认为是):

问题是,如果另一个线程试图在同一路径的不同连接上创建表,数据库将被锁定,因此将引发异常。为了防止出现这种情况,我可以采取以下措施:

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"));
  }
}
现在的代码是安全的,但也更笨重,因为我必须包装在锁每次使用。我的问题是,有没有一种方法可以将使用和锁结合起来,使它不那么笨重


理想情况下,它将以一种不依赖于内部操作涉及SQLiteConnection这一事实的方式完成。换句话说,为SQLiteConnection编写锁定包装是一个不太理想的解决方案,因为如果下次我的锁不涉及SQLite,问题将再次出现。

您可以有一个通用包装类,它接受IDisposable参数和相同的字符串参数,锁在哪个位置,在哪个位置可以使用

e、 g.(未测试代码):

另一种方法是一直使用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);
        }
    }
 }

我认为您应该使用(var connection=new…{)在
中编写一个try catch,而不是锁定。尝试创建一个表,如果它抛出异常,您就知道该表已经存在。更好的方法是使用类似
if(tableExists)的方法
将行添加到表中,否则创建它。您确定数据库会为不同的“tableName”抛出吗?这似乎是很容易序列化的事情。它确实对我产生了影响。我不确定为什么——它是在一个通用级别捕获的,不再明显。这不是表存在的问题。异常说“数据库已锁定”,这一定意味着另一个线程正在访问它。考虑到我当时正在做的事情,这是有意义的。不确定这里的锁定是否足够。CreateTable需要独占访问,同时从另一个线程查询/更新数据库是否有效?
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);
}
using(var lck = new SQLiteConnection("path").StartLock("path"))
    MyTableCreationHelper.CreateTable(lck.Object, "tableName"));
 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");