2014-02-13 50 views
1

我正在尝试同步要提供图像的webapi。当我请求一个特定的图像时,它会检查图像是否已经存在,如果有,则返回;如果不存在,则会创建并返回。.net文件访问同步

我的问题是,它显然不是像这样的线程安全;我有一个线程进来,并确定图像不存在,并开始创建它,而另一个请求进来,也确定图像不存在(只是还),并尝试创建它。我知道我可以锁定整个事情以避免这个问题,但我试图避免这个问题。将会有100,000个图像,我不明白为什么我需要停止所有线程阅读其他图像,因为只有一个图像尚不存在。有没有一种“通常”的方式来做到这一点?图像是由ID请求的,我可以锁定特定图像的ID吗?例如

List<long> _locks = new List<long>(); 
_locks.Add(17); 
lock(_locks[0]){...} 

它只是看起来不正确...肯定有更好的解决方案?

+0

你可以做的是,在你的'Read'上添加3次重试周期,相隔2秒。因此,如果您收到“文件访问异常”,大概在写入文件时,请等待并再次尝试读取。 –

+0

@ T.S。感谢队友,我想到了这一点,我猜想这是一个“备份”解决方案,但如果可以的话,我想尽量避免出现异常。我在多线程方面没有做太多的工作,所以试图弄清楚如何正确地做到这一点。 尝试锁定一个(静态)对象上的整个部分,平均响应时间从20ms到200ms ... !! – Andy

回答

2

这取决于您的服务器设置(单个或农场)。在单个服务器上,您可以使用共享的HashSet。文件名是一个很好的关键。你只需要在Set周围设置一个简短的锁定,这不会影响性能。

这是一个关于concurrent HashSet

+0

这最后运作良好。它将avg响应降低到12ms - 当然lock()优于200ms,比没有管理(因此有很多错误)和20ms更好。谢谢你的帮助。 – Andy

0

我的朋友的问题,你想避免“尝试为主”的方针,要避免“锁定”的办法,然而,你访问共享资源。尝试在任何托管的dll上调用corflags,然后离开命令窗口。然后去Windows资源管理器,并尝试删除该文件。你会得到“该文件正在使用”。即使Windows并没有完全摆脱文件的束缚,还有所有的缓存机制。当然,问题是你有所有的文件通过相同的锁。也许你可以做些什么来最大限度地减少这种情况。让我们来看看。这是完全未经测试的想法:

创建自定义的锁定对象

public class CustomLock 
{ 
    private object _lock = new object(); 
    private string _file; 

    public CustomLock(string file) 
    {_file = file;} 

    public object Read() 
    { 
     lock(_lock) 
     { 
      // read your file 
     } 
    } 

    public object Read() 
    { 
     lock(_lock) 
     { 
      // read your file 
     } 
    } 

    public override int GetHashCode() 
    { 
     // here your hash algorithm 
    } 

} 

现在,使用HashTableHashTable.Synchronized这里描述http://msdn.microsoft.com/en-us/library/system.collections.hashtable.synchronized%28v=vs.110%29.aspx,有你的锁

或者你也可以同步字典What's the best way of implementing a thread-safe Dictionary?的缓存。所以,现在会是这样的:

var custLock = GetCustLock(file); // This should always return CustomLock object, new or existing 
object file = custLock.Read(); 

据推测,采用这种设计,您将删除锁定在同一个地方的所有文件的瓶颈。请测试它。