2012-01-14 47 views
1

我有一个WCF服务和一个带有记录的资源(有ID来标识它们)。我想,只有1 ID可以同时访问 - 所以我写了一个小帮手资源:并发 - 每次编辑1个资源

public sealed class ConcurrencyIdManager 
{ 
    private static object _syncRootGrant = new object(); 
    private static List<int> _IdsInUse = new List<int>(); 

    ... // singleton   

    public void RequestAndWaitForIdGrant(int id) 
    { 
     lock (_syncRootGrant) 
     { 
      while (_IdsInUse.Where(i => i == id).Count() != 0) 
      { 
       Monitor.Wait(_syncRootGrant); 
      }    

      _IdsInUse.Add(id);     
     } 
    } 

    public void ReleaseGrantForId(int id) 
    { 
     lock (_syncRootGrant) 
     {     
      _IdsInUse.Remove(id); 

      Monitor.PulseAll(_syncRootGrant); 
     } 
    } 

所以在我的WCF服务,我有

public void UpdateMySpecialEntity(Entity foo) 
{ 
    ConcurrencyIdManager.Instance.RequestAndWaitForIdGrant(foo.Id); 
    try { 
     // do something with the entity foo 
    } 
    finally { ConcurrencyIdManager.Instance.ReleaseGrantForId(foo.Id); } 
} 

是实施正确的那么远? :-)

+0

如果我看了你的代码正确,你不跟1个资源在同一时间工作,你允许最多一个线程在任何给定时间对资源工作。每个资源只有一个可锁定的对象会不会更容易? – 2012-01-14 11:44:28

+0

我试图完成的任务是: *它应该被允许用多个线程更新具有不同ID的多个实体 *它不应该被允许用ID X同时更新一个实体。 我不太清楚“每个资源的可锁定对象”是什么意思?如果你的意思是每个资源项目 - 这是不可能的,因为数量是无限的(在这种情况下,假定资源是数据库) – damike 2012-01-14 12:08:44

+0

您正在使用哪个版本的.NET?你有权访问ConcurrentBag ?此外,这段代码将阻止对列表的整个访问,不仅限于特定的ID,所以不需要使用Wait和Pulse进行额外的阻塞。 – oleksii 2012-01-14 12:29:49

回答

0

如果我正在读你的笔记,你希望id的3 4和5可以同时编辑,但是两个id为5的线程可以阻止和等待对方。

在这种情况下,请使用并发的锁对象集合并对该对象的对象使用简单的锁。

例如在伪C#

ConcurrentDictionary<int,object> lockObjects = new ConcurrentDictionary<int,object) 
public void UpdateMySpecialEntity(Entity foo) 
{ 
    object idLock = lockObject.GetOrAdd(foo.id,new object()); 
    lock (idLock) 
    { 
    // do lock sensitive stuff in here. 
    } 
} 
+1

Thx很多!!我怎样才能安全地从lockObjects中删除内容? – damike 2013-10-21 11:47:33

+0

你可以尝试lockObject.TryRemove(foo.id) – 2013-10-22 16:20:09