线程安全队列机制

时间:2018-09-11 10:20:34

标签: c#

我的队列机制线程安全吗?我只是想知道我是否需要并发集合。我需要锁定入队方法吗?控制台以不正确的顺序显示队列计数,是否会影响Load方法中的maxQueueCount?我可以以某种方式进行改进吗?我希望队列具有最大大小,并且我不想再次将同一项目排队。

我有许多数据库源以及选择文档的存储过程。每个文档都有唯一的ID,但可能包含在许多数据源中。因此,我需要检查是否在我的数据流中处理了具有指定ID的文档。我不想阻塞我的队列,所以如果队列计数等于= 1000,我就不会排队新文档。

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Timers;

class Program
{
    public class Document : IItem
    {
        public Guid Id { get; set; }
    }

    static void Main()
    {
        var queueProvider = new Provider();
        var docs = new List<IItem>
        {
            new Document { Id = Guid.NewGuid() },
            new Document { Id = Guid.NewGuid() },
            new Document { Id = Guid.NewGuid() },
            new Document { Id = Guid.NewGuid() },
            new Document { Id = Guid.NewGuid() }
        };

        try
        {
            var tasks = new List<Task>();

            var task1 = Task.Factory.StartNew(() =>
            {
                var timer1 = new Timer(1000) { Interval = 1000 };
                timer1.Elapsed += (object sender, ElapsedEventArgs e) =>
                {
                    queueProvider.Load(docs, 1);
                };
                timer1.Enabled = true;
                timer1.Start();
            });
            tasks.Add(task1);

            var task2 = Task.Factory.StartNew(() =>
            {
                var timer1 = new Timer(1000) { Interval = 1000 };
                timer1.Elapsed += (object sender, ElapsedEventArgs e) =>
                {
                    queueProvider.Load(docs, 2);
                };
                timer1.Enabled = true;
                timer1.Start();
            });
            tasks.Add(task2);

            //Dequeue

            //var task3 = Task.Factory.StartNew(() =>
            //{
            //    var timer1 = new Timer(3000) { Interval = 1000 };
            //    timer1.Elapsed += (object sender, ElapsedEventArgs e) =>
            //    {
            //        queueProvider.Dequeue();
            //    };
            //    timer1.Enabled = true;
            //    timer1.Start();
            //});
            //tasks.Add(task3);

            Task.WaitAll(tasks.ToArray());
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }

        Console.ReadKey();
    }
}


public interface IItem
{
    Guid Id { get; set; }
}

public interface IProvider
{
    void Enqueue(IItem feedingItem, int id);
}

public class Provider : IProvider
{
    private readonly ConcurrentQueue<IItem> queue;
    private readonly ConcurrentDictionary<Guid, DateTime> inputBuffor;

    private readonly object locker = new object();

    private int maxQueueCount = 3;

    public Provider()
    {
        queue = new ConcurrentQueue<IItem>();
        inputBuffor = new ConcurrentDictionary<Guid, DateTime>();
    }

    public IItem Dequeue()
    {
        queue.TryDequeue(out var item);

        Console.WriteLine("Dequeue: " + item.Id);

        return item;
    }

    public void Enqueue(IItem item, int id)
    {
        //lock (locker)
        //{
        if (inputBuffor.TryAdd(item.Id, DateTime.Now))
        {
            queue.Enqueue(item);

            Console.WriteLine("Enqueue: " + item.Id + "taskId: " + id);
            Console.WriteLine("Count: " + queue.Count + " Buffor: " + inputBuffor.Count);
        }
        else
        {
            Console.WriteLine("Not Enqueue: " + item.Id + "taskId: " + id);
        }
        //}
    }

    public void Load(IEnumerable<IItem> data, int id)
    {
        foreach (var item in data)
        {
            if (queue.Count < maxQueueCount)
                Enqueue(item, id);
        }
    }
}

更新 我将Enqueu方法重命名为TryEnqueue,并添加了BlockingCollection而不是Concurent Collection。

      var task1 = Task.Factory.StartNew(() =>
                {
                    var timer1 = new Timer(1000) { Interval = 1000 };
                    timer1.Elapsed += (object sender, ElapsedEventArgs e) =>
                    {
                        foreach(var doc in docs) 
                        {
                               if (queueProvider.TryEnqueue(doc, 1))
                            {
                                Console.WriteLine("Enqueue: " + doc.Id + "taskId: 2");
                                Console.WriteLine("Count: " + queueProvider.QueueCount + " Buffor: " + queueProvider.BufforCount);
                            }
                            else
                            {
                                Console.WriteLine("Not Enqueue: " + doc.Id + "taskId: 2");
                            }
                        }


                    };
                    timer1.Enabled = true;
                    timer1.Start();
                });
                tasks.Add(task1);



        public bool TryEnqueue(IItem item, int id)
            {

                if (inputBuffor.TryAdd(item.Id, DateTime.Now))
                {
                    if (queue.TryAdd(item))
                    {
                        return true;
                    }
                }
                return false;
            }

 public IItem Dequeue()
    {
        queue.TryTake(out var item);

        return item;
    }

1 个答案:

答案 0 :(得分:1)

多个线程可以同时满足<Grid Grid.Row="0" Grid.Column="1" > <!--Remove the RowDefinitions/ColumnDefinitions--> <RichTextBox Name="txtLog"> <FlowDocument> <Paragraph FontSize="12">Hello, world!</Paragraph> </FlowDocument> </RichTextBox> </Grid> ,然后每个线程都将运行您的Enqueue方法并超过maxQueueCount。那绝对不是线程安全的。我会将其移至您的EnqueueMethod中,并用锁将其包围。