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

发布于 2024-08-30 13:23:25 字数 353 浏览 11 评论 0原文

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

与此同时,用户可以继续工作。有一些关键操作,我想将他锁定,而任何保存批次仍在异步运行。

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

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

我没有找到满足此要求的 .NET 3.5 c# 锁定方法。信号量不包含检查计数是否为 0 的方法。否则,使用具有无限最大计数的信号量即可。

I have some records, that I want to save to database asynchronously. I organize them into batches, then send them. As time passes, the batches are processed.

In the meanwhile the user can work on. There are some critical operations, that I want to lock him out from, while any save batch is still running asynchronously.

The save is done using a TableServiceContext and method .BeginSave() - but I think this should be irrelevant.

What I want to do is whenever an async save is started, increase a lock count, and when it completes, decrease the lock count so that it will be zero as soon as all have finished. I want to lock out the critical operation as long as the count is not zero. Furthermore I want to qualify the lock - by business object - for example.

I did not find a .NET 3.5 c# locking method, that does fulfil this requirement. A semaphore does not contain a method to check, if the count is 0. Otherwise a semaphore with unlimited max count would do.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

猫弦 2024-09-06 13:23:25

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

var s = new Semaphore(5, 5);

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

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

Actually the Semaphare does have a method for checking to see if the count is zero. Use the WaitOne method with a zero timeout. It will return a value indicating whether the semaphore was acquired. If it returns false then it was not acquired which implies that it's count is zero.

var s = new Semaphore(5, 5);

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

Console.WriteLine("no more left to acquire");
平定天下 2024-09-06 13:23:25

我假设当您说锁定用户时,在操作完成时它不是字面上的“锁定”,因为这会阻塞 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...
        }
    }
}

计数方面封装在 BusyState 中,然后在业务对象中使用它来指示任务开始和停止。可以挂钩引发开始和完成的事件来实现启用和禁用 UI 控件,以在异步操作完成时锁定用户。

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

I'm presuming that when you say lock the user out, it is not a literal "lock" whilst the operations are completed as this would block the UI thread and freeze the application when the lock was encountered. I'm assuming you mean that some state can be checked so that UI controls can be disabled/enabled.

Something like the following code could be used which is lock free:

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...
        }
    }
}

The counting aspect is encapsulated in BusyState which is then used in the business object to signal tasks starting and stopping. Raising started and completed events could be hooked to implement enabling and disabling UI controls to lock the user out whilst the async operations are being completed.

There are obviously loads of caveats here for handling error conditions, etc. So just some basic outline code...

半边脸i 2024-09-06 13:23:25

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

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

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
}

What is the purpose of the lock count if the only logic involves whether or not the value is non-zero?

If you want to do this on a type-by-type basis, you could take this approach:

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

    public static object SyncRoot { get { return lockObject; } }
}

(following the same pattern for other business objects)

If you then enclose your save and your critical operations in a block like this:

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

You will make saving and the critical operations mutually exclusive tasks.

Since you wanted it granular, you can cascade the locks like this:

lock(BusinessObject1.SyncRoot)
lock(BusinessObject2.SyncRoot)
lock(BusinessObject3.SyncRoot)
{
    // do work
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文