Обзор многопоточного кода C # - PullRequest
1 голос
/ 12 мая 2009

Важно ли, чтобы я блокировал очередь?

public abstract class ExpiringCache<TKey,TValue> : IDisposable 
{
    protected readonly object locker = new object();

    protected readonly Dictionary<TKey, TValue> cache =
        new Dictionary<TKey, TValue>();

    private readonly Queue<KeyValuePair<TKey, long>> queue =
        new Queue<KeyValuePair<TKey, long>>();

    private volatile bool dispose;

    private readonly Thread cleaningThread;

    private readonly long lifeSpanTicks;

    public ExpiringCache(TimeSpan lifeSpan)
    {
        // Validate lifeSpan

        if (lifeSpan.Ticks == 0)
        {
            throw new ArgumentOutOfRangeException
                ("lifeSpan", "Must be greater than zero.");
        }

        this.lifeSpanTicks = lifeSpan.Ticks;

        // Begin expiring expired items

        this.cleaningThread = new Thread(() =>
        {
            while (!this.dispose)
            {
                this.RemoveExpired();
                Thread.Sleep(1);
            }
        });

        this.cleaningThread.Start();
    }

    private void RemoveExpired()
    {
        if (this.queue.Count == 0)
        {
            return;
        }

        var pair = this.queue.Peek();

        if (pair.Value >= DateTime.Now.Ticks)
        {
            lock (this.locker)
            {
                this.cache.Remove(pair.Key);
            }

            this.queue.Dequeue();
        }
    }

    public bool Contains(TKey key)
    {
        lock (this.locker)
        {
            return this.cache.ContainsKey(key);
        }
    }

    public void Add(TKey key, TValue value)
    {
        lock (this.locker)
        {
            this.cache.Add(key, value);
        }

        this.queue.Enqueue(new KeyValuePair<TKey, long>
            (key, DateTime.Now.Ticks + this.lifeSpanTicks));
    }

    public void Dispose()
    {
        this.dispose = true;
    }
}

1 Ответ

5 голосов
/ 12 мая 2009

Недостаточно, например, заблокировать только метод Contains. Смотрите это:
http://blogs.msdn.com/jaredpar/archive/2009/02/16/a-more-usable-thread-safe-collection.aspx

По сути, вам нужно переосмыслить классический API очереди и использовать методы типа DequeueIfContains() вместо простого Contains() + Dequeue(), чтобы одна и та же блокировка применялась как к проверке Contains, так и к Dequeue операция.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...