2009-12-21 144 views
0

今天我得到了here nice answer这将解决我的问题。不幸的是,我忘了问如何锁定。锁定,问题问题

问题很简单 - 在服务器中,每个连接的客户端都会得到一个从1到500的唯一ID(可重用),这是最大的客户端。

答案是创建一个qeue,并为新连接使用等待元素,并在发布时将其返回。

我不确定我是否理解正确 - 我也应该用500个元素(整数)初始化queue,并且一个接一个地返回,一旦发布就返回?

如果是这样,这里锁定什么,我的问题主要是针对性能,因为我使用锁。

回答

1

如果你可以使用并行扩展走了ConcurrentQueue

如果你不能,你可以找到如何通过香草萨特

实现自己在this article顺便说一句,在乔恩斯基特答案是告诉你只是尝试去队列,如果是空的生成和使用。当你完成一个id时,只需将它排入队列即可。没有提及500个ID。如果您需要限制到500个ID,那么您将需要用500个ID来初始化队列,然后在队列为空时,而不是生成新队列。为此,consumer/producer pattern将更适合。

+0

这么简单的锁就够了。 – Thomas 2009-12-21 16:29:31

+0

+1 w/Minor modification ... BLOCKING只是一个解决应用程序问题的方法,当没有更多的连接可用时该怎么做。根据系统和上下文,你可能想要返回一个错误代码或抛出一个异常(或任何其他适当的错误处理范例)。优秀的答案否则。 – James 2009-12-21 16:31:38

0

我不明白你想做什么。

您可以为已用数字填充散列表。

而且您可以将其存储在应用程序范围内的变量中,并在访问该资源时使用Application.Lock和Application.Unlock方法。

0

像这样的东西?

/// <summary> 
/// Thread safe queue of client ids 
/// </summary> 
internal class SlotQueue 
{ 
    private readonly AutoResetEvent _event = new AutoResetEvent(false); 
    private readonly Queue<int> _items = new Queue<int>(); 
    private int _waitCount; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="SlotQueue"/> class. 
    /// </summary> 
    /// <param name="itemCount">The item count.</param> 
    public SlotQueue(int itemCount) 
    { 
     // Create queue items 
     for (int i = 0; i < itemCount; ++i) 
      _items.Enqueue(i); 
    } 

    /// <summary> 
    /// Gets number of clients waiting in the queue. 
    /// </summary> 
    public int QueueSize 
    { 
     get { return _waitCount; } 
    } 

    /// <summary> 
    /// 
    /// </summary> 
    /// <param name="waitTime">Number of milliseconds to wait for an id</param> 
    /// <returns></returns> 
    public int Deqeue(int waitTime) 
    { 
     // Thread safe check if we got any free items 
     lock (_items) 
     { 
      if (_items.Count > 0) 
       return _items.Dequeue(); 
     } 

     // Number of waiting clients. 
     Interlocked.Increment(ref _waitCount); 

     // wait for an item to get enqueued 
     // false = timeout 
     bool res = _event.WaitOne(waitTime); 
     if (!res) 
     { 
      Interlocked.Decrement(ref _waitCount); 
      return -1; 
     } 

     // try to fetch queued item 
     lock (_items) 
     { 
      if (_items.Count > 0) 
      { 
       Interlocked.Decrement(ref _waitCount); 
       return _items.Dequeue(); 
      } 
     } 

     // another thread got the last item between waitOne and the lock. 
     Interlocked.Decrement(ref _waitCount); 
     return -1; 
    } 

    /// <summary> 
    /// Enqueue a client ID 
    /// </summary> 
    /// <param name="id">Id to enqueue</param> 
    public void Enqueue(int id) 
    { 
     lock (_items) 
     { 
      _items.Enqueue(id); 
      if (_waitCount > 0) 
       _event.Set(); 
     } 
    } 
}