 |
|
 |
good article covering the basics I use a huge ring buffer or circular buffer in high speed image aquasition I wish I had found this article when i was learning how to implement that
|
|
|
|
 |
|
 |
I couldn't find the code in any of the three ZIP files, is there a way to get it?
|
|
|
|
 |
|
 |
Here is the test I used, it triggers the assert:
class CircularBufferTest
{
static QueueCB queue = new QueueCB();
static private void producer( object _count )
{
int count = (int) _count;
for( int i = 0; i < count; i++ )
{
queue.EnqueueBlocking( i );
}
}
static private void consumer( object _count )
{
int count = (int) _count;
for( int i = 0; i < count; i++ )
{
int result = (int) queue.DequeueBlocking();
Trace.Assert( result == i, String.Format("dequeued {0}, expected {1}", result, i ) );
}
}
public static void test( int count )
{
queue.SetSynchronousMode();
Thread producer = new Thread( new ParameterizedThreadStart( CircularBufferTest.producer ) );
Thread consumer = new Thread( new ParameterizedThreadStart( CircularBufferTest.consumer ) );
producer.Start( count );
consumer.Start( count );
producer.Join();
consumer.Join();
}
}
|
|
|
|
 |
|
 |
Sir, where can i download the GUI form? and the codes. i want to share it to my class.
|
|
|
|
 |
|
 |
The threads your running do not stop after the program halts execution.
|
|
|
|
 |
|
 |
Hi,
I created a tester for your class:
I used sync mode and blocking methods.
The producers does not stop and wait when it full, the consumer too, does 2 rounds of consuming and then stop(it sould stop immediately).
I think this project is very useful and I want to help u improve it.
10x
Oren
my code - pls cut and run it:
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using NiceVision.Common.Utils;
namespace NiceVision.Test.TestGUI
{
public class ProdConsTestForm : NiceVision.Common.Forms.NvcForm
{
private NiceVision.Common.GUI.NvcButton addProducerButton;
private NiceVision.Common.GUI.NvcButton addConsumerButton;
private System.ComponentModel.IContainer components = null;
private QueueCB myQueue = null;
private System.Random rand = null;
private int numOfProducers = 0;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.GroupBox groupBox2;
private NiceVision.Common.GUI.NvcTextBox producerCountTextBox;
private NiceVision.Common.GUI.NvcLabel nvcLabel1;
private NiceVision.Common.GUI.NvcLabel nvcLabel2;
private NiceVision.Common.GUI.NvcTextBox consumerCountTextBox;
private NiceVision.Common.GUI.NvcStatusBar nvcStatusBar1;
private NiceVision.Common.GUI.NvcLabel nvcLabel3;
private System.Windows.Forms.NumericUpDown producerSpeedNumericUpDown;
private System.Windows.Forms.NumericUpDown consumerSpeedNumericUpDown;
private NiceVision.Common.GUI.NvcLabel nvcLabel4;
private NiceVision.Common.GUI.NvcComboBox producersComboBox;
private NiceVision.Common.GUI.NvcLabel nvcLabel5;
private NiceVision.Common.GUI.NvcButton removeProducerButton;
private NiceVision.Common.GUI.NvcLabel nvcLabel6;
private NiceVision.Common.GUI.NvcComboBox consumersComboBox;
private NiceVision.Common.GUI.NvcButton removeConsumersButton;
private int numOfConsumers = 0;
public ProdConsTestForm()
{
// This call is required by the Windows Form Designer.
InitializeComponent();
// TODO: Add any initialization after the InitializeComponent call
myQueue = new QueueCB(10);
rand = new System.Random();
}
///
/// Clean up any resources being used.
///
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.addProducerButton = new NiceVision.Common.GUI.NvcButton(this.components);
this.addConsumerButton = new NiceVision.Common.GUI.NvcButton(this.components);
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.producersComboBox = new NiceVision.Common.GUI.NvcComboBox(this.components);
this.producerSpeedNumericUpDown = new System.Windows.Forms.NumericUpDown();
this.nvcLabel3 = new NiceVision.Common.GUI.NvcLabel(this.components);
this.nvcLabel1 = new NiceVision.Common.GUI.NvcLabel(this.components);
this.producerCountTextBox = new NiceVision.Common.GUI.NvcTextBox(this.components);
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.consumerSpeedNumericUpDown = new System.Windows.Forms.NumericUpDown();
this.nvcLabel4 = new NiceVision.Common.GUI.NvcLabel(this.components);
this.nvcLabel2 = new NiceVision.Common.GUI.NvcLabel(this.components);
this.consumerCountTextBox = new NiceVision.Common.GUI.NvcTextBox(this.components);
this.nvcStatusBar1 = new NiceVision.Common.GUI.NvcStatusBar(this.components);
this.nvcLabel5 = new NiceVision.Common.GUI.NvcLabel(this.components);
this.removeProducerButton = new NiceVision.Common.GUI.NvcButton(this.components);
this.nvcLabel6 = new NiceVision.Common.GUI.NvcLabel(this.components);
this.consumersComboBox = new NiceVision.Common.GUI.NvcComboBox(this.components);
this.removeConsumersButton = new NiceVision.Common.GUI.NvcButton(this.components);
this.groupBox1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.producerSpeedNumericUpDown)).BeginInit();
this.groupBox2.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.consumerSpeedNumericUpDown)).BeginInit();
this.SuspendLayout();
//
// addProducerButton
//
this.addProducerButton.BackColor = System.Drawing.Color.WhiteSmoke;
this.addProducerButton.Location = new System.Drawing.Point(16, 24);
this.addProducerButton.Name = "addProducerButton";
this.addProducerButton.Size = new System.Drawing.Size(48, 23);
this.addProducerButton.TabIndex = 0;
this.addProducerButton.Text = "Add";
this.addProducerButton.Click += new System.EventHandler(this.addProducerButton_Click);
//
// addConsumerButton
//
this.addConsumerButton.BackColor = System.Drawing.Color.WhiteSmoke;
this.addConsumerButton.Location = new System.Drawing.Point(16, 24);
this.addConsumerButton.Name = "addConsumerButton";
this.addConsumerButton.Size = new System.Drawing.Size(48, 23);
this.addConsumerButton.TabIndex = 1;
this.addConsumerButton.Text = "Add";
this.addConsumerButton.Click += new System.EventHandler(this.addConsumerButton_Click);
//
// groupBox1
//
this.groupBox1.Controls.AddRange(new System.Windows.Forms.Control[] {
this.removeProducerButton,
this.nvcLabel5,
this.producersComboBox,
this.producerSpeedNumericUpDown,
this.nvcLabel3,
this.nvcLabel1,
this.producerCountTextBox,
this.addProducerButton});
this.groupBox1.Location = new System.Drawing.Point(8, 8);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(368, 144);
this.groupBox1.TabIndex = 2;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Producer";
//
// producersComboBox
//
this.producersComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.producersComboBox.Location = new System.Drawing.Point(88, 112);
this.producersComboBox.Name = "producersComboBox";
this.producersComboBox.Size = new System.Drawing.Size(264, 21);
this.producersComboBox.TabIndex = 5;
//
// producerSpeedNumericUpDown
//
this.producerSpeedNumericUpDown.Location = new System.Drawing.Point(88, 88);
this.producerSpeedNumericUpDown.Name = "producerSpeedNumericUpDown";
this.producerSpeedNumericUpDown.Size = new System.Drawing.Size(40, 20);
this.producerSpeedNumericUpDown.TabIndex = 4;
this.producerSpeedNumericUpDown.Value = new System.Decimal(new int[] {
1,
0,
0,
0});
//
// nvcLabel3
//
this.nvcLabel3.BackColor = System.Drawing.Color.Transparent;
this.nvcLabel3.Location = new System.Drawing.Point(16, 88);
this.nvcLabel3.Name = "nvcLabel3";
this.nvcLabel3.Size = new System.Drawing.Size(72, 16);
this.nvcLabel3.TabIndex = 3;
this.nvcLabel3.Text = "Speed (sec.)";
//
// nvcLabel1
//
this.nvcLabel1.BackColor = System.Drawing.Color.Transparent;
this.nvcLabel1.Location = new System.Drawing.Point(16, 56);
this.nvcLabel1.Name = "nvcLabel1";
this.nvcLabel1.Size = new System.Drawing.Size(40, 16);
this.nvcLabel1.TabIndex = 2;
this.nvcLabel1.Text = "Count";
//
// producerCountTextBox
//
this.producerCountTextBox.Location = new System.Drawing.Point(56, 56);
this.producerCountTextBox.Name = "producerCountTextBox";
this.producerCountTextBox.ReadOnly = true;
this.producerCountTextBox.Size = new System.Drawing.Size(56, 20);
this.producerCountTextBox.TabIndex = 1;
this.producerCountTextBox.Text = "0";
//
// groupBox2
//
this.groupBox2.Controls.AddRange(new System.Windows.Forms.Control[] {
this.removeConsumersButton,
this.nvcLabel6,
this.consumersComboBox,
this.consumerSpeedNumericUpDown,
this.nvcLabel4,
this.nvcLabel2,
this.consumerCountTextBox,
this.addConsumerButton});
this.groupBox2.Location = new System.Drawing.Point(8, 160);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(368, 144);
this.groupBox2.TabIndex = 3;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Consumer";
//
// consumerSpeedNumericUpDown
//
this.consumerSpeedNumericUpDown.Location = new System.Drawing.Point(88, 88);
this.consumerSpeedNumericUpDown.Name = "consumerSpeedNumericUpDown";
this.consumerSpeedNumericUpDown.Size = new System.Drawing.Size(40, 20);
this.consumerSpeedNumericUpDown.TabIndex = 6;
this.consumerSpeedNumericUpDown.Value = new System.Decimal(new int[] {
1,
0,
0,
0});
//
// nvcLabel4
//
this.nvcLabel4.BackColor = System.Drawing.Color.Transparent;
this.nvcLabel4.Location = new System.Drawing.Point(16, 88);
this.nvcLabel4.Name = "nvcLabel4";
this.nvcLabel4.Size = new System.Drawing.Size(72, 16);
this.nvcLabel4.TabIndex = 5;
this.nvcLabel4.Text = "Speed (sec.)";
//
// nvcLabel2
//
this.nvcLabel2.BackColor = System.Drawing.Color.Transparent;
this.nvcLabel2.Location = new System.Drawing.Point(16, 56);
this.nvcLabel2.Name = "nvcLabel2";
this.nvcLabel2.Size = new System.Drawing.Size(40, 16);
this.nvcLabel2.TabIndex = 4;
this.nvcLabel2.Text = "Count";
//
// consumerCountTextBox
//
this.consumerCountTextBox.Location = new System.Drawing.Point(56, 56);
this.consumerCountTextBox.Name = "consumerCountTextBox";
this.consumerCountTextBox.ReadOnly = true;
this.consumerCountTextBox.Size = new System.Drawing.Size(56, 20);
this.consumerCountTextBox.TabIndex = 3;
this.consumerCountTextBox.Text = "0";
//
// nvcStatusBar1
//
this.nvcStatusBar1.Location = new System.Drawing.Point(0, 319);
this.nvcStatusBar1.Name = "nvcStatusBar1";
this.nvcStatusBar1.Size = new System.Drawing.Size(384, 22);
this.nvcStatusBar1.TabIndex = 4;
//
// nvcLabel5
//
this.nvcLabel5.BackColor = System.Drawing.Color.Transparent;
this.nvcLabel5.Location = new System.Drawing.Point(16, 112);
this.nvcLabel5.Name = "nvcLabel5";
this.nvcLabel5.Size = new System.Drawing.Size(60, 16);
this.nvcLabel5.TabIndex = 6;
this.nvcLabel5.Text = "Producers";
//
// removeProducerButton
//
this.removeProducerButton.BackColor = System.Drawing.Color.WhiteSmoke;
this.removeProducerButton.Location = new System.Drawing.Point(72, 24);
this.removeProducerButton.Name = "removeProducerButton";
this.removeProducerButton.Size = new System.Drawing.Size(56, 23);
this.removeProducerButton.TabIndex = 7;
this.removeProducerButton.Text = "Remove";
this.removeProducerButton.Click += new System.EventHandler(this.removeProducerButton_Click);
//
// nvcLabel6
//
this.nvcLabel6.BackColor = System.Drawing.Color.Transparent;
this.nvcLabel6.Location = new System.Drawing.Point(16, 112);
this.nvcLabel6.Name = "nvcLabel6";
this.nvcLabel6.Size = new System.Drawing.Size(60, 16);
this.nvcLabel6.TabIndex = 8;
this.nvcLabel6.Text = "Consumers";
//
// consumersComboBox
//
this.consumersComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.consumersComboBox.Location = new System.Drawing.Point(88, 112);
this.consumersComboBox.Name = "consumersComboBox";
this.consumersComboBox.Size = new System.Drawing.Size(264, 21);
this.consumersComboBox.TabIndex = 7;
//
// removeConsumersButton
//
this.removeConsumersButton.BackColor = System.Drawing.Color.WhiteSmoke;
this.removeConsumersButton.Location = new System.Drawing.Point(72, 24);
this.removeConsumersButton.Name = "removeConsumersButton";
this.removeConsumersButton.Size = new System.Drawing.Size(56, 23);
this.removeConsumersButton.TabIndex = 9;
this.removeConsumersButton.Text = "Remove";
this.removeConsumersButton.Click += new System.EventHandler(this.removeConsumersButton_Click);
//
// ProdConsTestForm
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(384, 341);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.nvcStatusBar1,
this.groupBox2,
this.groupBox1});
this.Name = "ProdConsTestForm";
this.Text = "Producer/Consumer Tester";
this.groupBox1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.producerSpeedNumericUpDown)).EndInit();
this.groupBox2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.consumerSpeedNumericUpDown)).EndInit();
this.ResumeLayout(false);
}
#endregion
private void addProducerButton_Click(object sender, System.EventArgs e)
{
// Create the thread object, passing in the invoke event method
// via a ThreadStart delegate. This does not start the thread.
ProdConsThread oThread = new ProdConsThread(new ThreadStart(AddProducer));
// Start the thread
oThread.Start();
producersComboBox.Items.Add(oThread);
producersComboBox.SelectedIndex = 0;
numOfProducers++;
producerCountTextBox.Text = numOfProducers + "";
}
public void AddProducer()
{
int speed = (int)producerSpeedNumericUpDown.Value * 1000;
while(true)
{
try
{
Thread.Sleep(speed);
int data = rand.Next(0, 100);
myQueue.EnqueueBlocking(data);
Console.WriteLine("[Producer][Thread{0}][Data:{1}][Speed:{2}][QueueCount:{3}]", Thread.CurrentThread.GetHashCode(), data, speed, myQueue.Count);
}
catch(Exception e)
{
Console.WriteLine("[ProducerException][Thread{0}][Info:{1}]", Thread.CurrentThread.GetHashCode(), e.Message);
}
}
}
private void addConsumerButton_Click(object sender, System.EventArgs e)
{
// Create the thread object, passing in the invoke event method
// via a ThreadStart delegate. This does not start the thread.
ProdConsThread oThread = new ProdConsThread(new ThreadStart(AddConsumer));
// Start the thread
oThread.Start();
consumersComboBox.Items.Add(oThread);
consumersComboBox.SelectedIndex = 0;
numOfConsumers++;
consumerCountTextBox.Text = numOfConsumers + "";
}
public void AddConsumer()
{
int speed = (int)consumerSpeedNumericUpDown.Value * 1000;
while(true)
{
try
{
Thread.Sleep(speed);
int data = (int) myQueue.DequeueBlocking();
Console.WriteLine("[Consumer][Thread{0}][Data:{1}][Speed:{2}][QueueCount:{3}]", Thread.CurrentThread.GetHashCode(), data, speed, myQueue.Count);
}
catch(Exception e)
{
Console.WriteLine("[ConsumerException][Thread{0}][Info:{1}]", Thread.CurrentThread.GetHashCode(), e.Message);
}
}
}
private void removeProducerButton_Click(object sender, System.EventArgs e)
{
ProdConsThread oThread = null;
try
{
oThread = (ProdConsThread)producersComboBox.SelectedItem;
oThread.Stop();
numOfProducers--;
producerCountTextBox.Text = numOfProducers + "";
producersComboBox.Items.Remove(oThread);
producersComboBox.SelectedIndex = 0;
}
catch(Exception exp){}
}
private void removeConsumersButton_Click(object sender, System.EventArgs e)
{
ProdConsThread oThread = null;
try
{
oThread = (ProdConsThread)consumersComboBox.SelectedItem;
oThread.Stop();
numOfConsumers--;
consumerCountTextBox.Text = numOfConsumers + "";
consumersComboBox.Items.Remove(oThread);
consumersComboBox.SelectedIndex = 0;
}
catch(Exception exp){}
}
}
}
|
|
|
|
 |
|
 |
Oren,
I will check it out this weekend when I have some time.
Thanks for using it.
Does your version do inter-process capability?
Bob H.
|
|
|
|
 |
|
 |
Oren,
Can you reproduce the problem using the GUI interface used in my article.
How should I set up all the boxes?
Bob H.
|
|
|
|
 |
|
 |
I tried but, cannot reproduce the bug on your gui. I simply open two thread - consumer and producer. Init new queue with 10 in the constructor.
producer get random number and call EnqueueBlocking(randNum) - loop this every 1 sec.
that's all the test.
My results are:
producer keep working (does not stop - count start from 0 every 9 elements)
then remove producer and start the consumer that call DequeueBlocking - loop this every 1 sec. it keep looping twice on the buffer (insted of stop when no data in)
10x
Oren
|
|
|
|
 |
|
 |
What's with the 10x?
|
|
|
|
 |
|
 |
it means thanks
|
|
|
|
 |
|
 |
I think there is a bug in Dequeue() methods perhaps only in Async Mode.
Anyone tried this. The test code used CopyTo() so it is ok.
-mm
mm
|
|
|
|
 |
|
 |
Is there a newer version?
Can you provide some code samples?
Can I use it for producer/consumer implementation?
10x and very good project
Oren, Israel
|
|
|
|
 |
|
 |
Oren,
Thanks.
Please feel free to improve/extend the code. I have been meaning to do an inter-process demo but haven't found the time.
I extended the .NET debugging trace (I think it is called) to use the circular buffer but haven't written that up yet.
Good luck but watch out for timing hazards.
Bob H.
|
|
|
|
 |
|
|
 |
|
 |
Can this code be used to exchange data between two processes? It looks from the description of your article that it is possible. But from code, it looks like it's meant to be used in same process space.
Regards,
Shital.
http://www.ShitalShah.com
|
|
|
|
 |
|
 |
Shital,
This article was just to introduce the Circular Buffer.
That inter-process comm would be a great extension.
Do you want to write it up or should I?
Bob H.
|
|
|
|
 |
|
 |
The implementation are identical for the following two ctors, what's the difference? why we need both?
public QueueCB(object o, System.Int32 len)
public QueueCB(System.Int32 len)
Thanks.
|
|
|
|
 |
|
 |
I think this was a cut and paste error.
What I wanted to do was allow some ctors with specific types of objects to be created (like an array of ints)and then to compare the speed of operations with the generic object. But I forgot to change from the generic type and I never got aroung to doing the check.
Thanks for catching that.
Bob H.
|
|
|
|
 |
|
 |
You are right on passing ValueType such as Byte[] or int[] instead of generic object will boost the speed. However, if implemented IEnumerator method Current being used, which boxing each ValueType to object, and caller need to un-boxing each Object to ValueType, then we will get big performance hit here. So, is there any good way to avoid it or .NET is not a good solution for fast-speed-required application, such as realtime data aquisition application? What's your opinion?
By the way, are you going to post updated source code?
Thanks a lot
|
|
|
|
 |
|
 |
Correct. A non-generic solution needs to be designed.
And also correct that I wanted to characterize .NET for some real-time processing--and the Circular Buffer is the place to start. Some kind of hybrid implementation using C++ and PInvoke will probably be needed.
I'll get back to the project one day and will update the code when it is improved. You are welcome to send-in or submit to CP your own code.
Bob H.
|
|
|
|
 |
|
 |
Hi
Only the source package is downloadable, the others are 404
|
|
|
|
 |