views:

79

answers:

3

Today I got here nice answer that will resolve my problem. Unfortunately, I forgot to ask how about locking.

The issue was simple - in the server, each connected client will get an unique ID (reusable) from 1 to 500, which is maximum of clients.

The answer was to create a qeue and use waiting elements for new connections and just return them back when they are released.

Im not sure whether I understand correctly - also I should init the qeue with 500 elements (ints) and just take them one by one and return back once released?

If so, what about locking here, my question was mainly aimed on performance because I was using lock.

A: 

i do not understand what you wanna do.

You can populate a hash table for used numbers.

And you can store it in an application wide variable and use Application.Lock and Application.Unlock methods while accessing to that resource.

Ozan BAYRAM
+1  A: 

If you can use Parallel Extensions go for a ConcurrentQueue

If you can't you can find how to implement your own in this article by Herb Sutter

By the way, the Jon Skeet answer is telling you to just try to unqueue and if empty generate and use. When you're done with an id, simply return it by enqueuing it. There's no reference to 500 ids. IF you need to limit to 500 ids then you will need to initialize the queue with your 500 ids and then, instead of generating new ones, BLOCK when the queue is empty. For that a consumer/producer pattern will be better suited.

Jorge Córdoba
So simple lock is enough.
Tomas
+1 w/Minor modification...BLOCKING is only one solution to the application problem of what to do when there are no more connections available. Depending on the system and the context you may want to return an error code or throw an exception instead (or any other error handling paradigm that's pertinent). Excellent answer otherwise.
James
A: 

Something like this?

/// <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();
        }
    }
}
jgauffin