如何清除所有已处理项目的队列?

时间:2014-10-12 10:53:55

标签: c# multithreading

您必须向客户发送全局对象队列。队列在其流程中不断充满新元素(一秒钟中的一个元素),这就是为什么你必须不断发送的原因。每个客户端都在一个单独的线程中提供。将对象发送到所有客户端后,必须将其从队列中删除。这似乎很容易,但是如何知道所有线程都已经发送了一个特定的对象?

我在套接字上做了一切。

Thread threadForClientSending = new Thread(delegate()
    {
        while (true)
        {
            try
            {
                List<SymbolsTable> [] localArrayList ;

                //main.que -- global queue
                foreach (var eachlist in localArrayList = main.que.ToArray())
                {
                    foreach (var item in eachlist)
                    {
                        byte[] message =
                            encoding.GetBytes((item.GetHashCode()%100).ToString() + " "+item.SDate +"\n\r");

                        client.Send(message);
                    }
                    Thread.Sleep(500);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                break;
            }
        }
    });

此类代码会将所有内容发送给所有人,但它不会清除队列。 如何清除所有已处理项目的队列?

public static ConcurrentQueue<List<SymbolsTable>> que = new ConcurrentQueue<List<SymbolsTable>>();

public partial class SymbolsTable
    {       
        public string SName { get; set; }
        public Nullable<double> SPrice { get; set; }
        public Nullable<int> SVolume { get; set; }
        public System.DateTime SDate { get; set; }
    }

1 个答案:

答案 0 :(得分:0)

注意:我强烈建议为每个客户端(服务器中的任务)定义本地队列,以实现最大的并发性和更清晰的代码。

使用CountDownEvent可以为每个项目保存线程访问权限,您可以实现所需,我们应该将其设置为向客户端发送数据的可用工作者数量。

这是我们如何做到的:

<强>解释

    public static ConcurrentQueue<List<SymbolsTable>> que = new ConcurrentQueue<List<SymbolsTable>>();
    public static CountdownEvent counter = new CountdownEvent(NumberOfThreads);
    private const int NumberOfThreads = 3; //for example we have 3 clients here

<强>发

 Thread threadForClientSending = new Thread(delegate()
            {
                while (true)
                {
                    try
                    {
                        List<SymbolsTable> list;
                        var peek = que.TryPeek(out list);
                        if (!peek)
                        {
                            Thread.Sleep(100); //nothing to pull
                            continue;
                        }

                        foreach (var item in list)
                        {
                            main.que -- global queue

                            byte[] message =
                            encoding.GetBytes((item.GetHashCode() % 100).ToString() + " " + item.SDate + "\n\r");

                            client.Send(message);

                            Thread.Sleep(500);
                        }

                        counter.Signal(); //the thread would signal itself as finished, and wait for others to finish the task

                        lock (que)
                        {
                            List<SymbolsTable> lastList;
                            if (que.TryPeek(out lastList) && lastList.Equals(list))
                            {
                                //just one of the threads would dequeue the item
                                que.TryDequeue(out lastList);

                                counter.Reset(); //reset counter for next iteration
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                        break;
                    }
                }
            });

这里我们使用TryPeek来访问队列中的项目,因此我们不会删除它,最后是:

                 lock (que)
                    {
                        List<SymbolsTable> lastList;
                        if (que.TryPeek(out lastList) && lastList.Equals(list))
                        {
                            //just one of the threads would dequeue the item
                            que.TryDequeue(out lastList);

                            counter.Reset(); //reset counter for next iteration
                        }
                    }

我们会锁定que,因此一次只有一个线程可以访问它,然后我们检查已处理的项目是否已从队列中删除,如果不是,我们将在此处将其删除。


更优雅的解决方案(以我的拙见):

正如您在之前的解决方案中看到的那样,我们阻止线程一起完成每个项目的任务,向每个线程添加本地队列将删除此阻塞机制,因此我们可以实现最大的并发性。

我建议像:

class GlobalQueue
{
    private readonly List<IMyTask> _subscribers=new List<IMyTask>();

    public void Subscribe(IMyTask task)
    {
        _subscribers.Add(task);
    }

    public void Unsubscribe(IMyTask task)
    {
        _subscribers.Remove(task);
    }

    public void Enqueue(List<SymbolsTable> table)
    {
        foreach (var s in _subscribers)
            s.Enqueue(table);
    }
}

interface IMyTask
{
    void Enqueue(List<SymbolsTable> table);
}

你的任务大致如下:

class MyTask : IMyTask
{
    private readonly ConcurrentQueue<List<SymbolsTable>> _localQueue = new ConcurrentQueue<List<SymbolsTable>>();
    private readonly Thread _thread;
    private bool _started;

    public void Enqueue(List<SymbolsTable> table)
    {
        _localQueue.Enqueue(table);
    }

    public MyTask()
    {
        _thread = new Thread(Execute);
    }

    public void Start()
    {
        _started = true;
        _thread.Start();
    }

    public void Stop()
    {
        _started = false;
    }

    private void Execute()
    {
        while (_started)
        {
            try
            {
                List<SymbolsTable> list;
                var peek = _localQueue.TryDequeue(out list);
                if (!peek)
                {
                    Thread.Sleep(100); //nothing to pull
                    continue;
                }

                foreach (var item in list)
                {
                    byte[] message =
                    encoding.GetBytes((item.GetHashCode() % 100).ToString() + " " + item.SDate + "\n\r");

                    client.Send(message);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                break;
            }
        }
    }
}