这个BlockingCollection不是我预期的FIFO

本文关键字:FIFO BlockingCollection 这个 | 更新日期: 2023-09-27 18:14:16

感谢您查看我的问题:我有一个(非gui线程)BlockingCollection,我一直认为将是FIFO(先进先出),但我现在意识到它不是

我已经在dotnetfiddle上粘贴了一个示例代码,但是因为它不运行多线程,所以看不到错误发生,但是可以看到代码

ok。我想要什么?我想在Visual Studio Express 2013 C# Winforms中创建第二个线程(非GUI),它就像一个工作室,可以按照发送它们的顺序执行传递的事情。

我选择了这样的结构:

nofQDo
|_addAction(|)
            |
            +-> static BlockingCollection foreach
                                          |
                                          +-> QDo.run(|)
                                                      |
                                                      +> QDoType.action(//code//)

这个奇怪的安排的原因是,我想有多达20或30 types的队列对象(我称这些都是QDoType_something),我很高兴的布局,但引擎不工作,如果我调用

QDoType_test gra = new QDoType_test("hey0");
nofQDo.addAction(gra);
QDoType_test grb = new QDoType_test("hey1");
nofQDo.addAction(grb);
QDoType_test grc = new QDoType_test("hey2");
nofQDo.addAction(grc);
 QDoType_test grd = new QDoType_test("hey3");
 nofQDo.addAction(grd);
 QDoType_test gre = new QDoType_test("hey4");
 nofQDo.addAction(gre);
 QDoType_test grf = new QDoType_test("hey5");
 nofQDo.addAction(grf);

00009::hey0
00009::hey1
00009::hey5
00009::hey3
00009::hey2
00009::hey4

00009::hey1
00009::hey0
00009::hey3
00009::hey2
00009::hey4
00009::hey5

所以它显然不是"FIFO",这是令人担忧的…是否有一种方法可以确保我的BlockingCollection是a) not gui线程b)只作为一个额外的线程运行,c)这个第二个线程总是运行FIFO(先进先出?)

下面是正确的代码:

= QDoType_test.cs =

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace QTest
{
    class QDoType_test : QDoType
    {
        String szout = "";
        private string ThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString("00000");
        public QDoType_test(String sent)
        {
            szout = sent;
        }
        public override void action()
        {
            System.Threading.Thread.Sleep(100);
            Console.WriteLine(ThreadId + "::" + szout);
        }
    }
}

= nofQDo.cs =

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace QTest
{
    class nofQDo
    {
        static BlockingCollection<QDo> queue = new BlockingCollection<QDo>(new ConcurrentQueue<QDo>()); //<--new ConcurrentQueue<QDo>() makes it FIFO
        public static void addAction(QDoType action)
        {
            QDo me = new QDo(action);
            queue.Add(me);
            Task.Factory.StartNew(() =>
            {
                foreach (QDo doThis in queue.GetConsumingEnumerable())
                {
                    doThis.run();
                }
            });
        }
    }
}

= QDoType.cs =

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace QTest
{
    /// <summary>
    /// This is a Parent Class for QDoType_whatever they are non 
    /// communicative and most exist to run db calls
    /// </summary>
    public abstract class QDoType
    {
        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *'
         * this is a parent class not meant to ever be instaciated   *
        '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
        public string uniqueid = "";
        public Action callback;
        public abstract void action();
        /// <summary>
        /// kept for the fact you might want 
        /// to debug where it went in the Queue
        /// </summary>
        /// <param name="uid"></param>
        public void setUniqueId(string uid)
        {
            uniqueid = uid;
        }
    }
}

= QDo.cs =

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace QTest
{
    class QDo
    {
        /***********
         * 
         * This class is the <T> umbrella for a real type that runs inside it
         * basically all this does in "run()" the QDoType;
         */
        public const bool DELETE_MODE = true;
        QDoType iam;
        public QDo(QDoType action)
        {
            DateTime dt = DateTime.Now;
            iam = action;
        }
        public void run()
        {
            iam.action();
            if (iam.callback != null) iam.callback();
        }
    }
}

这个BlockingCollection不是我预期的FIFO

好吧,我已经接近那里了,它只是确保消费者在生产者之前开始(即在构造函数中),仍然不是100%确定为什么这是有效的(但它确实如此!我向你保证100%!)它也在单台运行中进行了测试。

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace QTest
{
    class nofQDo
    {
        static BlockingCollection<QDo> queue = new BlockingCollection<QDo>(new ConcurrentQueue<QDo>()); //<--new ConcurrentQueue<QDo>() makes it FIFO
        static nofQDo()
        {
            Task.Factory.StartNew(() =>
            {
                foreach (QDo doThis in queue.GetConsumingEnumerable())
                {
                    doThis.run();
                }
            });
        }
        public static void addAction(QDoType action)
        {
            QDo me = new QDo(action);
            queue.Add(me);
        }
    }
}

现在
QDoType_test gra = new QDoType_test("hey0"); nofQDo.addAction(gra);
QDoType_test grb = new QDoType_test("hey1"); nofQDo.addAction(grb);
QDoType_test grc = new QDoType_test("hey2"); nofQDo.addAction(grc);
QDoType_test grd = new QDoType_test("hey3");  nofQDo.addAction(grd);
QDoType_test gre = new QDoType_test("hey4");  nofQDo.addAction(gre);
QDoType_test grf = new QDoType_test("hey5");  nofQDo.addAction(grf);

生产

00009::hey0
00009::hey1
00009::hey2
00009::hey3
00009::hey4
00009::hey5