如何防止在多个线程运行的方法是什么? [英] How to prevent a method from running across multiple threads?

查看:104
本文介绍了如何防止在多个线程运行的方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我工作的一个Web应用程序,几个用户可以更新相同的记录。因此,为了避免出现问题,如果用户在同一时间更新相同的记录,我保存它们在队列中的变化。当每个保存时,我想打电话给一个处理在另一个线程队列的方法,但我需要确保该方法不能在另一个线程运行,如果再次调用。我已经在这个问题看几个职位,但不知道什么是最适合我的情况。下面是我现在的代码。这是处理它的正确方法?

 公共静态类队列{
静态挥发布尔isProcessing;
静态挥发物柜=新的对象();

公共静态无效的过程(){
锁(柜){
如果{
isProcessing =真(isProcessing!);

//处理队列...

isProcessing = FALSE;
}
}
}
}


解决方案

新的答案



如果你坚持这些记录到一个数据库(或数据文件,或类似的持久性系统),你应该让这种潜在的系统来处理同步。由于 JohnSaunders指出, 数据库已经处理同时进行更新。






由于要坚持记录...的的由John提出的问题是你只同步在Web应用程序的单一实例的访问数据。尽管如此,有可能是在相同的时间(例如一个服务器群,这可能是一个好主意,如果你有高流量上)运行多个实例。在使用队列,以防止同时写入这个场景的不够好的becuse还有网页的多个实例之间的竞争条件。



在这种情况下,当你从不同实例相同的记录的更新,则垫层系统将具有反正处理碰撞,但它不能可靠地做到这一点,因为更新的顺序已丢失。



在除了这个问题,如果要使用该数据结构作为高速缓存,然后它会提供不正确的数据,因为它不知道在另一个中发生的更新实例。






随着中说,对于场景中它可能是值得使用一个线程安全队列。对于那些情况下,你可以使用 ConcurrentQueue (如我在提我原来的答复的末尾)。



我会保持我原来的答复,因为我在帮助理解.NET提供的线程同步机制(见价值其中我预设了一些)。






原来的答复



是足以防止多个线程同时接入到一个代码段(这是互斥)。



下面我注释掉你不需要的东西:

 公共静态类队列{
//静态挥发布尔isProcessing;
静态挥发物柜=新的对象();

公共静态无效的过程(){
锁(柜){
//如果{
// isProcessing =真(isProcessing!);

//处理队列...

// isProcessing = FALSE;
//}
}
}
}






通过试图在锁进入这一说,所有的线程将排起了长龙。这我理解的是不是你想要的。相反,你希望所有的其他线程跳过块,并只留下一个做的工作。这可以通过 Monitor.TryEnter 来完成:

 公共静态类队列
{
静态挥发物柜=新的对象();

公共静态无效的过程()
{
布尔lockWasTaken = FALSE;

{
如果(Monitor.TryEnter(柜))
{
lockWasTaken = TRUE;
//处理队列...
}
}
终于
{
如果(lockWasTaken)
{
监视器。退出(柜);
}
}
}
}






另一个很好的选择是使用的互锁

 公共静态类队列
{
静态INT状态= 0;

公共静态无效的过程()
{
布尔lockWasTaken = FALSE;

{
lockWasTaken = Interlocked.CompareExchange(REF状态,1,0)== 0;
如果(lockWasTaken)
{
//处理队列...
}
}
终于
{
如果( lockWasTaken)
{
Thread.VolatileWrite(REF状态,0);
}
}
}
}






反正你没有必要实现自己的线程安全的队列。你可以使用 ConcurrentQueue


I am working on a web application, where several users can update the same record. So to avoid a problem if users are updating the same record at the same time, I am saving their changes in a queue. When each save occurs, I want to call a method that processes the queue on another thread, but I need to make sure that the method cannot run in another thread if it is called again. I’ve read several posts on the subject, but not sure what is best for my situation. Below is the code I have now. Is this the correct way to handle it?

public static class Queue {
    static volatile bool isProcessing;
    static volatile object locker = new Object();

    public static void Process() {
        lock (locker) {
            if (!isProcessing) {
                isProcessing = true;

                //Process Queue...

                isProcessing = false;
            }
        }
    }
}

解决方案

New answer

If you are persisting these records to a database (or data files, or similar persistence system) you should let that underlying system handle the synchronization. As JohnSaunders pointed out Databases already handle simultaneous updates.


Given you want to persist the records... the problem presented by John is that you are only synchronizing the access to the data in a single instance of the web application. Still, there could be multiple instances running at the same time (for example in a server farm, which may be a good idea if you have high traffic). In this scenario using a queue to prevent simultaneous writes is not good enough becuse there is still a race condition among the multiple instances of the web page.

In that case, when you get updates for the same record from different instances, then the underlaying system will have to handle the collision anyway, yet it will not be able to do it reliably because the order of the updates has been lost.

In addition to that problem, if you are using this data structure as a cache, then it will provide incorrect data because it is not aware of the updates that happen in another instance.


With that said, for the scenarios where it may be worth to use a Thread-Safe Queue. For those cases you could use ConcurrentQueue (as I mention at the end of my original answer).

I'll keep my original answer, because I see value in helping understand the threading synchronization mechanism available in .NET (of which I preset a few).


Original answer

lock is enough to prevent the access of multiple threads to a code segment at the same time (this is mutual exclusion).

Here I have commented out what you don't need:

public static class Queue {
    // static volatile bool isProcessing;
    static volatile object locker = new Object();

    public static void Process() {
        lock (locker) {
            // if (!isProcessing) {
            //  isProcessing = true;

                //Process Queue...

            //  isProcessing = false;
            // }
        }
    }
}


With that said, all the threads that try to enter in the lock will be waiting in a queue. Which as I understand is not what you want. Instead you want all the other threads to skip the block and leave only one do the work. This can be done with Monitor.TryEnter:

public static class Queue
{
    static volatile object locker = new Object();

    public static void Process()
    {
        bool lockWasTaken = false;
        try
        {
            if (Monitor.TryEnter(locker))
            {
                lockWasTaken = true;
                //Process Queue...
            }
        }
        finally
        {
            if (lockWasTaken)
            {
                Monitor.Exit(locker);
            }
        }
    }
}


Another good alternative is to use Interlocked:

public static class Queue
{
    static int status = 0;

    public static void Process()
    {
        bool lockWasTaken = false;
        try
        {
            lockWasTaken = Interlocked.CompareExchange(ref status, 1, 0) == 0;
            if (lockWasTaken)
            {
                //Process Queue...
            }
        }
        finally
        {
            if (lockWasTaken)
            {
                Thread.VolatileWrite(ref status, 0);
            }
        }
    }
}


Anyway, you don't have the need to implement your own thread-safe queue. You could use ConcurrentQueue.

这篇关于如何防止在多个线程运行的方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆