IIS 和 C# 线程锁

安德鲁·沙利文

我对 C# 中的线程和 IIS 有疑问,我很感激有人的帮助。

我不是一个非常熟练的 C# 程序员,所以请善待,我会描述问题,然后我会展示我的一段代码,最后我会问两个问题。

问题描述

我有一个 web api 方法,需要在每次请求时访问磁盘上的同一个文件夹,但是如果已经有另一个线程访问提到的文件夹,则每次调用都不应访问该文件夹,换句话说,一次只有一个请求可以访问文件夹。

代码片段原始版本(使用监视器)

我使用实体类“banana”(:P) 给出了我的问题的示例,每个请求都包含一个香蕉的 id,这个 id 用于验证是否有另一个请求已经在访问该文件夹。

using System.Web.Hosting;
using System.Net.Http;
using System.Text;
using System.Threading;

[RoutePrefix("api/banana")]
public class BananaController
{
    private static readonly object bananasLocksAccess = new object();
    private static readonly Dictionary<long, object> bananasLocks = new Dictionary<long, object>();

    [Route("AccessBananaFolder")]
    [TokenAuthorize]
    [HttpGet]
    public BananaResponse AccessFolderWithBananaId(long bananaId)
    {
        BananaResponse r = new BananaResponse();
        Boolean bananaLockTaken = false;
        object bananaLocker = LockBanana(bananaId);
        try
        {
             System.Threading.Monitor.TryEnter(bananaLocker, ref bananaLockTaken);
             if (bananaLockTaken)
             {
                // safe code to access the folder of bananas
                // ...
                r = new BananaResponse("OK ACCESSING THE FOLDER");
             }
             else
             {
                r = new BananaResponse("COULD NOT ACCESS THE FOLDER RIGTH NOW, TRY AGAIN LATER");
             }
        }
        catch (Exception ex)
        {
            r = new BananaResponse("AN ERROR OCURRED ACCESSING THE FOLDER OF BANANAS");
        }
        finally
        {
            if (bananaLockTaken)
            {
                System.Threading.Monitor.Exit(bananaLocker);
            }
        }

        return r;
    }


    private static object LockBanana(long bananaId)
    {
        object bananaLocker;
        lock (bananasLocksAccess) {
            if (bananasLocks.ContainsKey(bananaId))
            {
                bananaLocker = bananasLocks[bananaId];
            }
            else
            {
                bananaLocker = new object();
                bananasLocks[bananaId] = bananaLocker;
            }
        }
        return bananaLocker;
    }
}

我的问题是

  • 1)这是解决C#问题的正确方法吗?

  • 2)由于 IIS 使用线程池管理请求/调用(IISExpress 是单线程吗?),是否有任何更改,因为两个不同的请求访问文件夹,因为由池中的同一线程管理?

非常感谢您提前!

================================================== ==========

更新!

代码片段版本 2(使用互斥锁)

好的,正如@STW在他的回复中所建议的那样,我做了一个新版本的代码,但是这次我使用互斥锁来限制对 Set 的访问,这个 set 包含当前正在访问香蕉文件夹的所有香蕉 ID(记住这是每个香蕉 id 的一个临时文件夹),这个新版本还改进了@Remus Rusanu在主要问题的回复中提到的清理问题。

    [RoutePrefix("api/banana")]
public class BananaController
{
    private static readonly Mutex bananasLocksAccess = new Mutex(false, "29c447fe-d146-4ea7-ac16-bb8e453ee065");
    private static readonly HashSet<long> bananasLocks = new HashSet<long>();

    [Route("AccessBananaFolder")]
    [TokenAuthorize]
    [HttpGet]
    public BananaResponse AccessFolderWithBananaId(long bananaId)
    {
        BananaResponse r = new BananaResponse();
        bool bananaLockTaken = false;
        try
        {
             bananaLockTaken = LockBanana(bananaId);
             if (bananaLockTaken)
             {
                // safe code to access the folder of bananas
                // ...
                r = new BananaResponse("OK ACCESSING THE FOLDER");
             }
             else
             {
                r = new BananaResponse("COULD NOT ACCESS THE FOLDER RIGTH NOW, TRY AGAIN LATER");
             }
        }
        catch (Exception ex)
        {
            r = new BananaResponse("AN ERROR OCURRED ACCESSING THE FOLDER OF BANANAS");
        }
        finally
        {
            if (bananaLockTaken)
            {
                UnlockBanana(bananaId);
            }
        }

        return r;
    }


    private static bool LockBanana(long bananaId)
    {
        bool lockTaken = false;
        try
        {
            lockTaken = bananasLocksAccess.WaitOne(0);
            if (lockTaken)
            {
                lockTaken = !bananasLocks.Contains(bananaId);
                if (lockTaken)
                {
                    bananasLocks.Add(bananaId);
                    lockTaken = true;
                }
            }
            bananasLocksAccess.ReleaseMutex();
        }
        catch (Exception e)
        {
            // could not complete the lock,  the user should try again later
        }
        return lockTaken;
    }

    private static void UnlockBanana(long bananaId)
    {
        try
        {
            bool lockTaken = bananasLocksAccess.WaitOne();
            if (lockTaken)
            {
                bananasLocks.Remove(bananaId);
            }
            bananasLocksAccess.ReleaseMutex();
        }
        catch (Exception e)
        {
            // the lock was released already
        }
    }

}
污水处理厂

由于您的代码在 IIS 中执行,因此您的代码可能有多个实例跨多个进程运行。跨进程同步需要操作系统级别的锁,而System.Threading.Mutex类是专门为此设计的。

Mutex有两种模式 - localnamed要跨进程工作,您需要使用命名模式,对于名称,我建议对随机生成的 GUID 进行硬编码。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

C ++ 11多线程锁和原子基元

来自分类Dev

在C ++中将无锁和全锁线程同步与原子TestAndSet混合

来自分类Dev

具有共享互斥锁和类实例的C ++ 11线程

来自分类Dev

具有共享互斥锁和类实例的C ++ 11线程

来自分类Dev

C,XPMEM和锁

来自分类Dev

C ++多线程互斥锁“重置”

来自分类Dev

线程安全销毁C中的读写锁

来自分类Dev

一组线程的C ++互斥锁

来自分类Dev

锁内的新线程-C#

来自分类Dev

线程安全销毁C中的读写锁

来自分类Dev

带锁的C#中的线程

来自分类Dev

同一线程获取和释放多个锁

来自分类Dev

Python 的线程和多进程锁不起作用

来自分类Dev

条件变量和互斥锁的线程池(大概)锁定问题

来自分类Dev

带有广播信号的线程和互斥锁

来自分类Dev

C ++,线程和指针

来自分类Dev

C ++,信号和线程

来自分类Dev

C ++ 98和线程

来自分类Dev

C ++对象和线程

来自分类Dev

C#线程示例代码无锁工作

来自分类Dev

如何在C中为多线程使用互斥锁?

来自分类Dev

如何在多线程 C++ 程序中读取锁

来自分类Dev

C++ 无锁队列因多线程而崩溃

来自分类Dev

在c中使用互斥锁进行多线程并一次运行一个线程

来自分类Dev

是否将所有代码放在互斥锁和互斥锁之间会使多线程(ness)失去意义

来自分类Dev

使用Powershell SDK和C#启用IIS

来自分类Dev

C ++中的向量和线程

来自分类Dev

C ++虚函数和线程

来自分类Dev

无锁和无等待的线程安全延迟初始化