Reputation: 2546
thanks for looking at my question: I have a (non gui thread) BlockingCollection
that I had always assumed would be FIFO (First in First Out) but I now realise it isn't
I have pasted an example of the code on dotnetfiddle but because it doesn't run multithreads you can't see the error happening, but you can see the code
ok. So what did I want? I wanted to make a second thread (non GUI) in Visual Studio Express 2013 C# Winforms
that would be like a work house that would do the things it was passed in the order it was sent them.
I opted for a structure that is like this:
nofQDo
|_addAction(|)
|
+-> static BlockingCollection foreach
|
+-> QDo.run(|)
|
+> QDoType.action(//code//)
the reason for this strange arrangement was that I wanted to have up to 20 or 30 types
of queue object (I call these all QDoType_something
) and I am happy with the layout out but the engine doesn't work if I call
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);
I get
00009::hey0
00009::hey1
00009::hey5
00009::hey3
00009::hey2
00009::hey4
or
00009::hey1
00009::hey0
00009::hey3
00009::hey2
00009::hey4
00009::hey5
so it clearly isn't "FIFO
" and this is alarming.. is there a way to ensure that my BlockingCollection
is a) not gui
thread b) only ever running as one extra thread and c) that this second thread is always running FIFO
(First in First Out?)
as requested: Here is the code proper:
=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();
}
}
}
Upvotes: 1
Views: 1412
Reputation: 2546
ok I was nearly there it was merely making sure that the consumer started before the producer (i.e. in the constructor), still not 100% sure why this works (but it definitely does! I assure you 100%!) it is tested on single unit runs too.
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);
}
}
}
so now
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);
produces
00009::hey0
00009::hey1
00009::hey2
00009::hey3
00009::hey4
00009::hey5
Upvotes: 1