.NET 3.5 C#没有提供锁定所需的功能:再次计数异步保存,直到0

.NET 3.5 C#没有提供锁定所需的功能:再次计数异步保存,直到0,c#,.net,locking,semaphore,C#,.net,Locking,Semaphore,我有一些记录,我想异步保存到数据库。我把它们分批组织起来,然后发送出去。随着时间的推移,批次将被处理 同时,用户还可以继续工作。当任何保存批处理仍在异步运行时,有一些关键操作我想将其锁定 保存是使用TableServiceContext和方法.BeginSave()完成的,但我认为这应该是无关的 我想做的是,每当异步保存启动时,增加锁计数,当它完成时,减少锁计数,以便在所有操作完成后立即为零。我想锁定关键操作,只要计数不为零。此外,我想通过业务对象来限定锁,例如 我没有找到一个.NET3.5C#

我有一些记录,我想异步保存到数据库。我把它们分批组织起来,然后发送出去。随着时间的推移,批次将被处理

同时,用户还可以继续工作。当任何保存批处理仍在异步运行时,有一些关键操作我想将其锁定

保存是使用TableServiceContext和方法.BeginSave()完成的,但我认为这应该是无关的

我想做的是,每当异步保存启动时,增加锁计数,当它完成时,减少锁计数,以便在所有操作完成后立即为零。我想锁定关键操作,只要计数不为零。此外,我想通过业务对象来限定锁,例如


我没有找到一个.NET3.5C#锁定方法,它确实满足了这个要求。如果计数为0,则信号量不包含要检查的方法。否则,具有无限最大计数的信号量就可以了

如果唯一的逻辑涉及值是否为非零,那么锁计数的目的是什么

如果要逐个类型执行此操作,可以采用以下方法:

public class BusinessObject1
{
    private static readonly object lockObject = new object();

    public static object SyncRoot { get { return lockObject; } }
}
(其他业务对象采用相同的模式)

如果随后将保存操作和关键操作放在一个块中,如下所示:

lock(BusinessObject1.SyncRoot)
{
    // do work
}
lock(BusinessObject1.SyncRoot)
lock(BusinessObject2.SyncRoot)
lock(BusinessObject3.SyncRoot)
{
    // do work
}
您将使保存和关键操作任务互斥

因为您希望它是细粒度的,所以可以像这样级联锁:

lock(BusinessObject1.SyncRoot)
{
    // do work
}
lock(BusinessObject1.SyncRoot)
lock(BusinessObject2.SyncRoot)
lock(BusinessObject3.SyncRoot)
{
    // do work
}

实际上,
Semaphare
确实有一个检查计数是否为零的方法。使用具有零超时的WaitOne方法。它将返回一个值,指示是否获取了信号量。如果它返回false,则它未被获取,这意味着它的计数为零

var s = new Semaphore(5, 5);

while (s.WaitOne(0))
{
  Console.WriteLine("acquired");  
}

Console.WriteLine("no more left to acquire");

我假设,当您说锁定用户时,在操作完成时,它不是字面上的“锁定”,因为这会阻止UI线程,并在遇到锁定时冻结应用程序。我假设您的意思是可以检查某些状态,以便禁用/启用UI控件

可以使用类似以下代码的无锁代码:

public class BusyState
{
    private int isBusy;

    public void SignalTaskStarted()
    {
        Interlocked.Increment(ref isBusy);
    }

    public void SignalTaskFinished()
    {
        if (Interlocked.Decrement(ref isBusy) < 0)
        {
            throw new InvalidOperationException("No tasks started.");
        }
    }

    public bool IsBusy()
    {
        return Thread.VolatileRead(ref isBusy) > 0;
    }
}

public class BusinessObject
{
    private readonly BusyState busyState = new BusyState();

    public void Save()
    {
        //Raise a "Started" event to disable UI controls...

        //Start a few async tasks which call CallbackFromAsyncTask when finished.

        //Start task 1
        busyState.SignalTaskStarted();

        //Start task 2
        busyState.SignalTaskStarted();

        //Start task 3
        busyState.SignalTaskStarted();
    }

    private void CallbackFromAsyncTask()
    {
        busyState.SignalTaskFinished();

        if (!busyState.IsBusy())
        {
            //Raise a "Completed" event to enable UI controls...
        }
    }
}
公共类总线状态
{
私家车很忙;
public void SignalTaskStarted()
{
联锁。增量(参考忙);
}
public void SignalTaskFinished()
{
if(联锁减量(参考忙)<0)
{
抛出新的InvalidOperationException(“未启动任务”);
}
}
公共图书馆很忙
{
返回线程volatireRead(ref isBusy)>0;
}
}
公共类BusinessObject
{
private readonly BusyState BusyState=new BusyState();
公共作废保存()
{
//引发“已启动”事件以禁用UI控件。。。
//启动一些异步任务,这些任务在完成时调用callbackromasynctask。
//启动任务1
busyState.SignalTaskStarted();
//开始任务2
busyState.SignalTaskStarted();
//开始任务3
busyState.SignalTaskStarted();
}
私有void callbackromasynctask()
{
busyState.SignalTaskFinished();
如果(!busyState.IsBusy())
{
//引发“已完成”事件以启用UI控件。。。
}
}
}
计数方面封装在BusyState中,然后在业务对象中使用它来通知任务开始和停止。可以挂接引发已启动和已完成事件,以实现启用和禁用UI控件,从而在异步操作完成时锁定用户

这里显然有很多关于处理错误条件等的警告,所以只需要一些基本的大纲代码