ASP.NET锁定线程的方法

发布于 2024-08-27 10:13:43 字数 941 浏览 4 评论 0原文

我正在使用 C# 开发 ASP.NET 表单 Web 应用程序。我有一种为客户创建新订单的方法。它看起来与此类似;

    private string CreateOrder(string userName) {
        // Fetch current order
        Order order = FetchOrder(userName);
        if (order.OrderId == 0) {
            // Has no order yet, create a new one
            order.OrderNumber = Utility.GenerateOrderNumber();
            order.Save();
        }
        return order;
    }

这里的问题是,两个请求(线程)中的 1 个客户可能会导致该方法被调用两次,而另一个线程也在该方法内。这可能会导致创建两个订单。

如何正确锁定此方法,以便每个客户一次只能由一个线程执行?

我试过;

    Mutex mutex = null;
    private string CreateOrder(string userName) {
        if (mutex == null) {
            mutex = new Mutex(true, userName);
        }
        mutex.WaitOne();
        // Code from above
        mutex.ReleaseMutex();
        mutex = null;
        return order;
    }

这可行,但在某些情况下它会挂在 WaitOne 上,我不知道为什么。是否有错误,或者我应该使用其他方法来锁定?

谢谢

I'm developing an ASP.NET forms webapplication using C#. I have a method which creates a new Order for a customer. It looks similar to this;

    private string CreateOrder(string userName) {
        // Fetch current order
        Order order = FetchOrder(userName);
        if (order.OrderId == 0) {
            // Has no order yet, create a new one
            order.OrderNumber = Utility.GenerateOrderNumber();
            order.Save();
        }
        return order;
    }

The problem here is, it is possible that 1 customer in two requests (threads) could cause this method to be called twice while another thread is also inside this method. This can cause two orders to be created.

How can I properly lock this method, so it can only be executed by one thread at a time per customer?

I tried;

    Mutex mutex = null;
    private string CreateOrder(string userName) {
        if (mutex == null) {
            mutex = new Mutex(true, userName);
        }
        mutex.WaitOne();
        // Code from above
        mutex.ReleaseMutex();
        mutex = null;
        return order;
    }

This works, but on some occasions it hangs on WaitOne and I don't know why. Is there an error, or should I use another method to lock?

Thanks

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

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

发布评论

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

评论(6

我早已燃尽 2024-09-03 10:13:43

mutex 构造函数中为 initiallyOwned 传递 false。如果您创建互斥锁并最初拥有它,则需要再次调用 ReleaseMutex

Pass false for initiallyOwned in the mutex ctor. If you create the mutex and initially own it, you need to call ReleaseMutex again.

暗地喜欢 2024-09-03 10:13:43

释放互斥体时,您应该始终尝试最后。另外,请确保密钥正确(用户名)

Mutex mutex = null;
private string CreateOrder(string userName) {
    mutex = mutex ?? new Mutex(true, userName);
    mutex.WaitOne();
    try{
    // Code from above
    }finally{
    mutex.ReleaseMutex();
    }
    mutex = null;
    return order;
}

You should always try finally when releasing mutex. Also, make sure that the key is correct(userName)

Mutex mutex = null;
private string CreateOrder(string userName) {
    mutex = mutex ?? new Mutex(true, userName);
    mutex.WaitOne();
    try{
    // Code from above
    }finally{
    mutex.ReleaseMutex();
    }
    mutex = null;
    return order;
}
心清如水 2024-09-03 10:13:43

在您的代码中,您正在惰性地创建互斥体。这会导致竞争条件。
例如,当您从另一个线程调用 WaitOne() 时,可能会发生互斥体仅部分构造的情况。
您也可能创建两个互斥体实例。
等等...

您可以通过急切地创建实例来避免这种情况 - 即如迈克尔的代码所示。
(确保将其初始化为非拥有状态。)

Mutex 是内核级同步原语 - 它比 Monitor 更昂贵(这就是 lock 使用的功能。)。

In your code, you are creating the mutex lazily. This leads to race conditions.
E.g. it can happen that the mutex is only partially constructed when you call WaitOne() from another thread.
It can also happen that you create two mutex instances.
etc...

You can avoid this by creating the instance eagerly - i.e. as in Michael's code.
(Be sure to initialize it to a non-owned state.)

Mutex is a kernel-level synchronization primitive - it is more expensive than Monitor (that is what lock uses.).

最丧也最甜 2024-09-03 10:13:43

除非我漏掉了什么,否则你不能用普通的锁吗?

private object _locker = new object();

private string CreateOrder(string userName)
{
    lock(_locker)
    {
        // Fetch current order
        Order order = FetchOrder(userName);
        if (order.OrderId == 0)
        {
            // Has no order yet, create a new one
            order.OrderNumber = Utility.GenerateOrderNumber();
            order.Save();
        }
        return order;
    }
}

Unless I'm missing something, can't you just use a regular lock?

private object _locker = new object();

private string CreateOrder(string userName)
{
    lock(_locker)
    {
        // Fetch current order
        Order order = FetchOrder(userName);
        if (order.OrderId == 0)
        {
            // Has no order yet, create a new one
            order.OrderNumber = Utility.GenerateOrderNumber();
            order.Save();
        }
        return order;
    }
}
捶死心动 2024-09-03 10:13:43

我一直避免锁定基于 Web 的应用程序 - 让 Web 服务器处理线程,而是构建重复检测。

您认为通过锁定 CreateOrder 会得到什么?在我看来,您可以避免同时创建两个订单,但最终仍然会创建两个订单。

I have always avoided locking in a web-based application - let the web server deal with the threads, and instead build in duplicate detection.

What do you think you're going to get by locking on the CreateOrder? It seems to me that you may avoid creating two order simultaneously, but you're still going to end up with two orders created.

长亭外,古道边 2024-09-03 10:13:43

这样做更容易:

在某个地方定义一个类,如下所示:

public class MyLocks {
    public static object OrderLock;
    static MyLocks() {
        OrderLock = new object();
    }
}

然后在使用锁时执行以下操作:

lock(MyLocks.OrderLock) {
    // put your code here
}

那么它不是很复杂。无论出于何种目的定义锁都是轻量级的,因为它们只是内存中非常小的对象,在多个线程中都处于活动状态。

Its easier to do this:

define a class somewhere like so:

public class MyLocks {
    public static object OrderLock;
    static MyLocks() {
        OrderLock = new object();
    }
}

then when using the lock do this:

lock(MyLocks.OrderLock) {
    // put your code here
}

Its not very complicated then. Its light weight to define locks for whatever purpose as they are just very tiny objects in memory that are alive across multiple threads.

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