Best way to refresh a Treeview c# task timer - c#

I have a process (Task) that works with a Tree (C#). That tree is loaded from a postgre database. That process is listening to events. When an event occurs, the Tree is updated.
With another process (Task), I use the same Tree, to reflect the changes in a Treeview using a Timer.
It's very slow. So there is something that I'm doing wrong...
I need help to know what is the best approach to do this, information about books, examples of Thread, BackgroundWorker, Timer, Task, Real Time Systems, and so on.
Thanks!
Regards.

This is an example similar to the code I am developing...There are 3 Classes: A, B and C. A is the "master" class. It has a list of B objects and a List of B Threads. Each B Object has a list of C Classes and C Threads.
C class is ready when an operation is done (in the example, put the variable "cIsReady" to true. When all the cObjects in the list, of object B, are ready, then "bIsReady" is set to true. When all the bObjects in the List, of object A, are ready, then "aIsReady" is set to true.
public class A
{
private List<B> bList;
private List<Thread> threadBList;
private bool aIsReady;
/// <summary>
/// List of classes managed by A Class.
/// </summary>
public List<B> BList
{
get
{
return bList;
}
set
{
bList = value;
}
}
/// <summary>
/// List of Threads. Each Thread manages a B Class.
/// </summary>
public List<Thread> ThreadBList
{
get
{
return threadBList;
}
set
{
threadBList = value;
}
}
/// <summary>
/// Indicates when A is ready.
/// </summary>
public bool AIsReady
{
get
{
return aIsReady;
}
set
{
aIsReady = value;
}
}
/// <summary>
/// Constructor.
/// </summary>
public A()
{
}
/// <summary>
/// Starts the A Class.
/// </summary>
public void startA()
{
this.bList = new List<B>();
this.threadBList = new List<Thread>();
// for example
int numberOfBClasses = 3;
for (int i = 0; i < numberOfBClasses; ++i)
{
B bObject = new B();
this.bList.Add(bObject);
Thread bThread = new Thread(bObject.startB);
bThread.IsBackground = true;
this.threadBList.Add(bThread);
} // for (int i = 0; i < numberOfBClasses; ++i)
// Start all the B Threads.
for (int i = 0; i < numberOfBClasses; ++i)
{
this.threadBList[i].Start();
} // for (int i = 0; i < numberOfBClasses; ++i)
while (!aIsReady)
{
foreach (B bObject in this.bList)
{
if (bObject.BIsReady)
{
this.aIsReady = true;
} // if (bObject.BIsReady)
else
{
this.aIsReady = false;
} // else [ if (bObject.BIsReady) ]
} // foreach (B bObject in this.bList)
} // while (!aIsReady)
this.aIsReady = true;
}
} // public class A
public class B
{
private List<C> cList;
private List<Thread> threadCList;
private bool bIsReady;
/// <summary>
/// List of classes managed by B Class.
/// </summary>
public List<C> CList
{
get
{
return cList;
}
set
{
cList = value;
}
}
/// <summary>
/// List of Threads. Each Thread manages a C Class.
/// </summary>
public List<Thread> ThreadCList
{
get
{
return threadCList;
}
set
{
threadCList = value;
}
}
/// <summary>
/// Indicates when B is ready.
/// </summary>
public bool BIsReady
{
get
{
return bIsReady;
}
set
{
bIsReady = value;
}
}
/// <summary>
/// Constructor
/// </summary>
public B()
{
}
/// <summary>
/// Start B
/// </summary>
public void startB()
{
this.cList = new List<C>();
this.threadCList = new List<Thread>();
// for example
int numberOfCClasses = 5;
for (int i = 0; i < numberOfCClasses; ++i)
{
C cObject = new C();
this.cList.Add(cObject);
Thread cThread = new Thread(cObject.startC);
cThread.IsBackground = true;
this.threadCList.Add(cThread);
} // for (int i = 0; i < numberOfCClasses; ++i)
// Start all the C Threads.
for (int i = 0; i < numberOfCClasses; ++i)
{
this.threadCList[i].Start();
} // for (int i = 0; i < numberOfCClasses; ++i)
while (!bIsReady)
{
foreach (C cObject in this.cList)
{
if (cObject.CIsReady)
{
this.bIsReady = true;
} // if (cObject.CIsReady)
else
{
this.bIsReady = false;
} // else [ if (cObject.CIsReady) ]
} // foreach (C in this.cList)
} // while (!bIsReady)
this.bIsReady = true;
}
} // public class B
public class C
{
private bool cIsReady;
/// <summary>
/// Indicates that the object is ready.
/// </summary>
public bool CIsReady
{
get
{
return cIsReady;
}
set
{
cIsReady = value;
}
}
/// <summary>
/// Constructor.
/// </summary>
public C()
{
}
/// <summary>
/// Starts C.
/// </summary>
public void startC()
{
this.cIsReady = true;
}
} // public class C
So, when I put the following code under, a form load event for example:
A aObject = new A();
Thread aThread = new Thread(aObject.startA);
while (!aObject.AIsReady)
{
Thread.Sleep(100);
}
MessageBox.Show("A is Ready");
The aObject never is ready...
Thanks!

Related

xamarin.ios the mp3 stops plaiying when the screen switches off

i'm developing an app, and i need to play music from url.
i'm using this code, and it works fine.
But, while a song is playing, and the screen switches off, then the music stops. I need that the music continues playing until its end, even if the screen switches off.
i suppose i have to change this file, but i don't know how:
using System;
using AudioToolbox;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
namespace SecondoSenso
{
/// <summary>
/// A Class to hold the AudioBuffer with all setting together
/// </summary>
internal class AudioBuffer
{
public IntPtr Buffer { get; set; }
public List<AudioStreamPacketDescription> PacketDescriptions { get; set; }
public int CurrentOffset { get; set; }
public bool IsInUse { get; set; }
}
/// <summary>
/// Wrapper around OutputQueue and AudioFileStream to allow streaming of various filetypes
/// </summary>
public class StreamingPlayback : IDisposable
{
public bool boolDispose = false;
public event EventHandler Finished;
public event Action<OutputAudioQueue> OutputReady;
// the AudioToolbox decoder
AudioFileStream fileStream;
int bufferSize = 128 * 256;
List<AudioBuffer> outputBuffers;
AudioBuffer currentBuffer;
// Maximum buffers
int maxBufferCount = 4;
// Keep track of all queued up buffers, so that we know that the playback finished
int queuedBufferCount = 0;
// Current Filestream Position - if we don't keep track we don't know when to push the last uncompleted buffer
long currentByteCount = 0;
//Used to trigger a dump of the last buffer.
bool lastPacket;
public OutputAudioQueue OutputQueue;
public bool Started { get; private set; }
public float Volume {
get {
return OutputQueue.Volume;
}
set {
OutputQueue.Volume = value;
}
}
/// <summary>
/// Defines the size forearch buffer, when using a slow source use more buffers with lower buffersizes
/// </summary>
public int BufferSize {
get {
return bufferSize;
}
set {
bufferSize = value;
}
}
/// <summary>
/// Defines the maximum Number of Buffers to use, the count can only change after Reset is called or the
/// StreamingPlayback is freshly instantiated
/// </summary>
public int MaxBufferCount {
get {
return maxBufferCount;
}
set {
maxBufferCount = value;
}
}
public StreamingPlayback () : this (AudioFileType.MP3)
{
}
public StreamingPlayback (AudioFileType type)
{
fileStream = new AudioFileStream (type);
fileStream.PacketDecoded += AudioPacketDecoded;
fileStream.PropertyFound += AudioPropertyFound;
}
public void Reset ()
{
if (fileStream != null) {
fileStream.Close ();
fileStream = new AudioFileStream (AudioFileType.MP3);
currentByteCount = 0;
fileStream.PacketDecoded += AudioPacketDecoded;
fileStream.PropertyFound += AudioPropertyFound;
}
}
public void ResetOutputQueue ()
{
if (OutputQueue != null) {
OutputQueue.Stop (true);
OutputQueue.Reset ();
foreach (AudioBuffer buf in outputBuffers) {
buf.PacketDescriptions.Clear ();
OutputQueue.FreeBuffer (buf.Buffer);
}
outputBuffers = null;
OutputQueue.Dispose ();
}
}
/// <summary>
/// Stops the OutputQueue
/// </summary>
public void Pause ()
{
OutputQueue.Pause ();
Started = false;
}
/// <summary>
/// Starts the OutputQueue
/// </summary>
public void Play ()
{
OutputQueue.Start ();
Started = true;
}
/// <summary>
/// Main methode to kick off the streaming, just send the bytes to this method
/// </summary>
public void ParseBytes (byte[] buffer, int count, bool discontinuity, bool lastPacket)
{
this.lastPacket = lastPacket;
fileStream.ParseBytes (buffer, 0, count, discontinuity);
}
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
public void Dispose(int tt) {
}
/// <summary>
/// Cleaning up all the native Resource
/// </summary>
protected virtual void Dispose (bool disposing)
{
if (disposing) {
if (OutputQueue != null)
OutputQueue.Stop(true);
if (outputBuffers != null) {
foreach (var b in outputBuffers)
OutputQueue.FreeBuffer (b.Buffer);
outputBuffers.Clear ();
outputBuffers = null;
}
if (fileStream != null) {
fileStream.Close ();
fileStream = null;
}
if (OutputQueue != null) {
OutputQueue.Dispose ();
OutputQueue = null;
}
}
}
/// <summary>
/// Saving the decoded Packets to our active Buffer, if the Buffer is full queue it into the OutputQueue
/// and wait until another buffer gets freed up
/// </summary>
void AudioPacketDecoded (object sender, PacketReceivedEventArgs args)
{
foreach (var p in args.PacketDescriptions) {
currentByteCount += p.DataByteSize;
AudioStreamPacketDescription pd = p;
int left = bufferSize - currentBuffer.CurrentOffset;
if (left < pd.DataByteSize) {
EnqueueBuffer ();
WaitForBuffer ();
}
AudioQueue.FillAudioData (currentBuffer.Buffer, currentBuffer.CurrentOffset, args.InputData, (int)pd.StartOffset, pd.DataByteSize);
// Set new offset for this packet
pd.StartOffset = currentBuffer.CurrentOffset;
// Add the packet to our Buffer
currentBuffer.PacketDescriptions.Add (pd);
// Add the Size so that we know how much is in the buffer
currentBuffer.CurrentOffset += pd.DataByteSize;
}
if ((fileStream != null && currentByteCount == fileStream.DataByteCount) || lastPacket)
EnqueueBuffer ();
}
/// <summary>
/// Flush the current buffer and close the whole thing up
/// </summary>
public void FlushAndClose ()
{
if (OutputQueue != null) {
EnqueueBuffer ();
OutputQueue.Flush ();
}
Dispose ();
}
/// <summary>
/// Enqueue the active buffer to the OutputQueue
/// </summary>
void EnqueueBuffer ()
{
currentBuffer.IsInUse = true;
OutputQueue.EnqueueBuffer (currentBuffer.Buffer, currentBuffer.CurrentOffset, currentBuffer.PacketDescriptions.ToArray ());
queuedBufferCount++;
StartQueueIfNeeded ();
}
/// <summary>
/// Wait until a buffer is freed up
/// </summary>
void WaitForBuffer ()
{
int curIndex = outputBuffers.IndexOf (currentBuffer);
currentBuffer = outputBuffers [curIndex < outputBuffers.Count - 1 ? curIndex + 1 : 0];
lock (currentBuffer) {
while (currentBuffer.IsInUse)
Monitor.Wait (currentBuffer);
}
}
void StartQueueIfNeeded ()
{
if (Started)
return;
Play ();
}
/// <summary>
/// When a AudioProperty in the fed packets is found this callback is called
/// </summary>
void AudioPropertyFound (object sender, PropertyFoundEventArgs args)
{
if (args.Property == AudioFileStreamProperty.ReadyToProducePackets) {
Started = false;
if (OutputQueue != null)
OutputQueue.Dispose ();
OutputQueue = new OutputAudioQueue (fileStream.StreamBasicDescription);
if (OutputReady != null)
OutputReady (OutputQueue);
currentByteCount = 0;
OutputQueue.BufferCompleted += HandleBufferCompleted;
outputBuffers = new List<AudioBuffer> ();
for (int i = 0; i < MaxBufferCount; i++) {
IntPtr outBuffer;
OutputQueue.AllocateBuffer (BufferSize, out outBuffer);
outputBuffers.Add (new AudioBuffer () {
Buffer = outBuffer,
PacketDescriptions = new List<AudioStreamPacketDescription> ()
});
}
currentBuffer = outputBuffers.First ();
OutputQueue.MagicCookie = fileStream.MagicCookie;
}
}
/// <summary>
/// Is called when a buffer is completly read and can be freed up
/// </summary>
void HandleBufferCompleted (object sender, BufferCompletedEventArgs e)
{
queuedBufferCount--;
IntPtr buf = e.IntPtrBuffer;
foreach (var buffer in outputBuffers) {
if (buffer.Buffer != buf)
continue;
// free Buffer
buffer.PacketDescriptions.Clear ();
buffer.CurrentOffset = 0;
lock (buffer) {
buffer.IsInUse = false;
Monitor.Pulse (buffer);
}
}
if (queuedBufferCount == 0 && Finished != null)
Finished (this, new EventArgs ());
}
}
}
how can i change the code to allow that?
thanks in advance for helps.
Put this following code in your AppDelegate.csin the FinishedLaunchingmethod.
NSError sessionError = null;
AVAudioSession.SharedInstance().SetCategory(AVAudioSession.CategoryAmbient, out sessionError);
AVAudioSession.SharedInstance().SetActive(true, out sessionError);
Apps get suspended when the phone is put to sleep. If you wan't your app to continue executing, you have to register for background execution.
Here is a nice guide Jonathan Sagorin (if you don't mind putting it over from Swift/obj-c).
Basically the class you are looking for is AVAudioSession and it's SetActive Method to activate a background audio session.

Make a C# implementation of a LinkedRingBuffer Thread Safe

I have three questions:
What do you generally think about my approach to solve the given problem?
What do you think I could further improve performance wise?
The most important one: How do I make my implementation really thread safe?
At first the simplified scenario I'm in:
I am communicating via a messaging system with different devices. I am receiving and sending thousands and thousands of messages in a rather short time period. I am inside of a multithreading environment so a lot of different tasks are sending and expecting messages. For the message reception an event driven approach got us a lot of trouble in the sense of making it thread safe.
I have a few Receiver tasks which get messages from outside and have to deliver these messages to a lot of consumer tasks.
So I came up with a different approach:
Why not have a history of a few thousand messages where every new message is enqueued and the consumer tasks can search backwards from the newest item to the last processed item in order to get all newly arrived messages. Of course this has to be fast and thread safe.
I came up with the idea of a linked ring buffer and implemented the following:
public class LinkedRingBuffer<T>
{
private LinkedRingBufferNode<T> firstNode;
private LinkedRingBufferNode<T> lastNode;
public LinkedRingBuffer(int capacity)
{
Capacity = capacity;
Count = 0;
}
/// <summary>
/// Maximum count of items inside the buffer
/// </summary>
public int Capacity { get; }
/// <summary>
/// Actual count of items inside the buffer
/// </summary>
public int Count { get; private set; }
/// <summary>
/// Get value of the oldest buffer entry
/// </summary>
/// <returns></returns>
public T GetFirst()
{
return firstNode.Item;
}
/// <summary>
/// Get value of the newest buffer entry
/// </summary>
/// <returns></returns>
public T GetLast()
{
return lastNode.Item;
}
/// <summary>
/// Add item at the end of the buffer.
/// If capacity is reached the link to the oldest item is deleted.
/// </summary>
public void Add(T item)
{
/* create node and set to last one */
var node = new LinkedRingBufferNode<T>(lastNode, item);
lastNode = node;
/* if it is the first node, the created is also the first */
if (firstNode == null)
firstNode = node;
/* check for capacity reach */
Count++;
if(Count > Capacity)
{/* deleted all links to the current first so that its eventually gc collected */
Count = Capacity;
firstNode = firstNode.NextNode;
firstNode.PreviousNode = null;
}
}
/// <summary>
/// Iterate through the buffer from the oldest to the newest item
/// </summary>
public IEnumerable<T> LastToFirst()
{
var current = lastNode;
while(current != null)
{
yield return current.Item;
current = current.PreviousNode;
}
}
/// <summary>
/// Iterate through the buffer from the newest to the oldest item
/// </summary>
public IEnumerable<T> FirstToLast()
{
var current = firstNode;
while (current != null)
{
yield return current.Item;
current = current.NextNode;
}
}
/// <summary>
/// Iterate through the buffer from the oldest to given item.
/// If item doesn't exist it iterates until it reaches the newest
/// </summary>
public IEnumerable<T> LastToReference(T item)
{
var current = lastNode;
while (current != null)
{
yield return current.Item;
if (current.Item.Equals(item))
break;
current = current.PreviousNode;
}
}
/// <summary>
/// Iterate through the buffer from the newest to given item.
/// If item doesn't exist it iterates until it reaches the oldest
/// </summary>
public IEnumerable<T> FirstToReference(T item)
{
var current = firstNode;
while (current != null)
{
yield return current.Item;
if (current.Item.Equals(item))
break;
current = current.PreviousNode;
}
}
/// <summary>
/// Represents a linked node inside the buffer and holds the data
/// </summary>
private class LinkedRingBufferNode<A>
{
public LinkedRingBufferNode(LinkedRingBufferNode<A> previousNode, A item)
{
Item = item;
NextNode = null;
PreviousNode = previousNode;
if(previousNode != null)
previousNode.NextNode = this;
}
internal A Item { get; }
internal LinkedRingBufferNode<A> PreviousNode { get; set; }
internal LinkedRingBufferNode<A> NextNode { get; private set; }
}
}
But unfortunately I'm kind of new to the multithreading environment, so how would I make this buffer thread safe for multiple reads and writes?
Thanks!
I think the simplest way would be to have a synchronization object which you would lock on, whenever performing thread-critical code. The code within a lock block is called the critical section, and can only be accessed by one thread at a time. Any other thread wishing to access it will wait, until the lock is released.
Definition and initialization:
private object Synchro;
public LinkedRingBuffer(int capacity)
{
Synchro = new object();
// Other constructor code
}
Usage:
public T GetFirst()
{
lock(Synchro)
{
return firstNode.Item;
}
}
When writing thread-safe code, locking some parts may seem obvious. But if you're not sure whether or not to lock a statement or block of code, for both read and write safety you need to consider:
Whether or not this code can influence the behavior or result of any other locked critical sections.
Whether or not any other locked critical sections can influence this code's behavior or result.
You will also need to rewrite some of your auto-implemented properties to have a backing field. It should be pretty straightforward, however...
Your usage of yield return, while being pretty smart and efficient in a single-thread context, will cause trouble in a multi-threaded context. This is because yield return doesn't release a lock statement (and it shouldn't). You will have to perform materialization in a wrapper, wherever you use yield return.
Your thread-safe code looks like this:
public class LinkedRingBuffer<T>
{
private LinkedRingBufferNode<T> firstNode;
private LinkedRingBufferNode<T> lastNode;
private object Synchro;
public LinkedRingBuffer(int capacity)
{
Synchro = new object();
Capacity = capacity;
Count = 0;
}
/// <summary>
/// Maximum count of items inside the buffer
/// </summary>
public int Capacity { get; }
/// <summary>
/// Actual count of items inside the buffer
/// </summary>
public int Count
{
get
{
lock (Synchro)
{
return _count;
}
}
private set
{
_count = value;
}
}
private int _count;
/// <summary>
/// Get value of the oldest buffer entry
/// </summary>
/// <returns></returns>
public T GetFirst()
{
lock (Synchro)
{
return firstNode.Item;
}
}
/// <summary>
/// Get value of the newest buffer entry
/// </summary>
/// <returns></returns>
public T GetLast()
{
lock (Synchro)
{
return lastNode.Item;
}
}
/// <summary>
/// Add item at the end of the buffer.
/// If capacity is reached the link to the oldest item is deleted.
/// </summary>
public void Add(T item)
{
lock (Synchro)
{
/* create node and set to last one */
var node = new LinkedRingBufferNode<T>(lastNode, item);
lastNode = node;
/* if it is the first node, the created is also the first */
if (firstNode == null)
firstNode = node;
/* check for capacity reach */
Count++;
if (Count > Capacity)
{
/* deleted all links to the current first so that its eventually gc collected */
Count = Capacity;
firstNode = firstNode.NextNode;
firstNode.PreviousNode = null;
}
}
}
/// <summary>
/// Iterate through the buffer from the oldest to the newest item
/// </summary>
public IEnumerable<T> LastToFirst()
{
lock (Synchro)
{
var materialized = LastToFirstInner().ToList();
return materialized;
}
}
private IEnumerable<T> LastToFirstInner()
{
var current = lastNode;
while (current != null)
{
yield return current.Item;
current = current.PreviousNode;
}
}
/// <summary>
/// Iterate through the buffer from the newest to the oldest item
/// </summary>
public IEnumerable<T> FirstToLast()
{
lock (Synchro)
{
var materialized = FirstToLastInner().ToList();
return materialized;
}
}
private IEnumerable<T> FirstToLastInner()
{
var current = firstNode;
while (current != null)
{
yield return current.Item;
current = current.NextNode;
}
}
/// <summary>
/// Iterate through the buffer from the oldest to given item.
/// If item doesn't exist it iterates until it reaches the newest
/// </summary>
public IEnumerable<T> LastToReference(T item)
{
lock (Synchro)
{
var materialized = LastToReferenceInner(item).ToList();
return materialized;
}
}
private IEnumerable<T> LastToReferenceInner(T item)
{
var current = lastNode;
while (current != null)
{
yield return current.Item;
if (current.Item.Equals(item))
break;
current = current.PreviousNode;
}
}
/// <summary>
/// Iterate through the buffer from the newest to given item.
/// If item doesn't exist it iterates until it reaches the oldest
/// </summary>
public IEnumerable<T> FirstToReference(T item)
{
lock (Synchro)
{
var materialized = FirstToReferenceInner(item).ToList();
return materialized;
}
}
private IEnumerable<T> FirstToReferenceInner(T item)
{
var current = firstNode;
while (current != null)
{
yield return current.Item;
if (current.Item.Equals(item))
break;
current = current.PreviousNode;
}
}
/// <summary>
/// Represents a linked node inside the buffer and holds the data
/// </summary>
private class LinkedRingBufferNode<A>
{
public LinkedRingBufferNode(LinkedRingBufferNode<A> previousNode, A item)
{
Item = item;
NextNode = null;
PreviousNode = previousNode;
if (previousNode != null)
previousNode.NextNode = this;
}
internal A Item { get; }
internal LinkedRingBufferNode<A> PreviousNode { get; set; }
internal LinkedRingBufferNode<A> NextNode { get; private set; }
}
}
There can be some optimizations done, for example you don't need to create the LinkedRingBufferNode objects inside the critical section, however you would have to copy the lastNode value to a local variable inside a critical section, before creating the object.

How to dispose System.Threading.EventWaitHandle in Mono?

The System.Threading.EventWaitHandle type does not contain a definition for 'dispose'.
How am I supposed to dispose of the EventWaitHandle when I want to kill the object in which it is contained? I've been having a serious memory leak problem and I've tried setting the EventWaitHandle to null and the memory leak persists.
Here's my code (I'm using Bob Craven's library, I added only the dispose() method):
using System;
using System.Threading;
namespace Rlc.Cron
{
public class CronObject
{
public delegate void CronEvent(CronObject cronObject);
public event CronEvent OnCronTrigger;
public event CronEvent OnStarted;
public event CronEvent OnStopped;
public event CronEvent OnThreadAbort;
private CronObjectDataContext _cronObjectDataContext;
private Guid _id = Guid.NewGuid();
private object _startStopLock = new object();
private EventWaitHandle _wh = new AutoResetEvent(false);
private Thread _thread;
public bool _isStarted;
private bool _isStopRequested;
private DateTime _nextCronTrigger;
public Guid Id { get { return _id; } }
public object Object { get { return _cronObjectDataContext.Object; } }
public DateTime LastTigger { get { return _cronObjectDataContext.LastTrigger; } }
/// <summary>
/// Initializes a new instance of the <see cref="CronObject"/> class.
/// </summary>
/// <param name="cronObjectDataContext">The cron object data context.</param>
public CronObject(CronObjectDataContext cronObjectDataContext)
{
if (cronObjectDataContext == null)
{
throw new ArgumentNullException("cronObjectDataContext");
}
if (cronObjectDataContext.Object == null)
{
throw new ArgumentException("cronObjectDataContext.Object");
}
if (cronObjectDataContext.CronSchedules == null || cronObjectDataContext.CronSchedules.Count == 0)
{
throw new ArgumentException("cronObjectDataContext.CronSchedules");
}
_cronObjectDataContext = cronObjectDataContext;
}
/// <summary>
/// Starts this instance.
/// </summary>
/// <returns></returns>
public bool Start()
{
lock (_startStopLock)
{
// Can't start if already started.
//
if (_isStarted)
{
return false;
}
_isStarted = true;
_isStopRequested = false;
// This is a long running process. Need to run on a thread
// outside the thread pool.
//
_thread = new Thread(ThreadRoutine);
_thread.Start();
}
// Raise the started event.
//
if(OnStarted != null)
{
OnStarted(this);
}
return true;
}
/// <summary>
/// Stops this instance.
/// </summary>
/// <returns></returns>
public bool Stop()
{
lock (_startStopLock)
{
// Can't stop if not started.
//
if (!_isStarted)
{
return false;
}
_isStarted = false;
_isStopRequested = true;
// Signal the thread to wake up early
//
_wh.Set();
// Wait for the thread to join.
//
if(!_thread.Join(5000))
{
_thread.Abort();
// Raise the thread abort event.
//
if(OnThreadAbort != null)
{
OnThreadAbort(this);
}
}
}
// Raise the stopped event.
//
if(OnStopped != null)
{
OnStopped(this);
}
return true;
}
public void dispose(){
this.Stop ();
this.OnCronTrigger = null;
this.OnStarted=null;
this.OnStopped=null;
this.OnThreadAbort=null;
this._cronObjectDataContext=null;
this._startStopLock = null;
this._wh = null;
this._thread=null;
}
/// <summary>
/// Cron object thread routine.
/// </summary>
private void ThreadRoutine()
{
// Continue until stop is requested.
//
while(!_isStopRequested)
{
// Determine the next cron trigger
//
DetermineNextCronTrigger(out _nextCronTrigger);
TimeSpan sleepSpan = _nextCronTrigger - DateTime.Now;
if(sleepSpan.TotalMilliseconds < 0)
{
// Next trigger is in the past. Trigger the right away.
//
sleepSpan = new TimeSpan(0, 0, 0, 0, 50);
}
// Wait here for the timespan or until I am triggered
// to wake up.
//
if(!_wh.WaitOne(sleepSpan))
{
// Timespan is up...raise the trigger event
//
if(OnCronTrigger != null)
{
OnCronTrigger(this);
}
// Update the last trigger time.
//
_cronObjectDataContext.LastTrigger = DateTime.Now;
}
}
}
/// <summary>
/// Determines the next cron trigger.
/// </summary>
/// <param name="nextTrigger">The next trigger.</param>
private void DetermineNextCronTrigger(out DateTime nextTrigger)
{
nextTrigger = DateTime.MaxValue;
foreach (CronSchedule cronSchedule in _cronObjectDataContext.CronSchedules)
{
DateTime thisTrigger;
if(cronSchedule.GetNext(LastTigger, out thisTrigger))
{
if (thisTrigger < nextTrigger)
{
nextTrigger = thisTrigger;
}
}
}
}
~CronObject(){
Console.WriteLine ("===================CRONOBJECT DESTROYED!!===============");
}
}
}

C# - finite list or limited list?

I am wondering about a certain functionality in C#...
I would like to have a List<Object> MyList();, which I could .Add(new Object()) finite amount of times. Let's say I added 5 items, and if I would add sixth, then the last item would be destroyed, and this sixth element would be put on top of the list.
Is there any built-in mechanism in c# that does that?
There is no build-in collection in Framework as Servy said. However, you can make a CircularBuffer like this -
namespace DataStructures
{
class Program
{
static void Main(string[] args)
{
var buffer = new CircularBuffer<int>(capacity: 3);
while (true)
{
int value;
var input = Console.ReadLine();
if (int.TryParse(input, out value))
{
buffer.Write(value);
continue;
}
break;
}
Console.WriteLine("Buffer: ");
while (!buffer.IsEmpty)
{
Console.WriteLine(buffer.Read());
}
Console.ReadLine();
}
}
}
namespace DataStructures
{
public class CircularBuffer<T>
{
private T[] _buffer;
private int _start;
private int _end;
public CircularBuffer()
: this(capacity: 3)
{
}
public CircularBuffer(int capacity)
{
_buffer = new T[capacity + 1];
_start = 0;
_end = 0;
}
public void Write(T value)
{
_buffer[_end] = value;
_end = (_end + 1) % _buffer.Length;
if (_end == _start)
{
_start = (_start + 1) % _buffer.Length;
}
}
public T Read()
{
T result = _buffer[_start];
_start = (_start + 1) % _buffer.Length;
return result;
}
public int Capacity
{
get { return _buffer.Length; }
}
public bool IsEmpty
{
get { return _end == _start; }
}
public bool IsFull
{
get { return (_end + 1) % _buffer.Length == _start; }
}
}
}
Above code is from PluralSight - Scott Allen's C# Generics.
None of the built in collections will do this, but you can easily make your own class that has an internal list that has this behavior when adding an item. It's not particularly difficult, but writing out all of the methods that a standard list would use and implementing all of the interfaces List does could be a bit tedious.
In my core library, I have something called a LimitedQueue<T>. This is probably similar to what you're after (you could easily modify it to be a List<T> instead). (Source on GitHub)
using System.Collections.Generic;
namespace Molten.Core
{
/// <summary>
/// Represents a limited set of first-in, first-out objects.
/// </summary>
/// <typeparam name="T">The type of each object to store.</typeparam>
public class LimitedQueue<T> : Queue<T>
{
/// <summary>
/// Stores the local limit instance.
/// </summary>
private int limit = -1;
/// <summary>
/// Sets the limit of this LimitedQueue. If the new limit is greater than the count of items in the queue, the queue will be trimmed.
/// </summary>
public int Limit
{
get
{
return limit;
}
set
{
limit = value;
while (Count > limit)
{
Dequeue();
}
}
}
/// <summary>
/// Initializes a new instance of the LimitedQueue class.
/// </summary>
/// <param name="limit">The maximum number of items to store.</param>
public LimitedQueue(int limit)
: base(limit)
{
this.Limit = limit;
}
/// <summary>
/// Adds a new item to the queue. After adding the item, if the count of items is greater than the limit, the first item in the queue is removed.
/// </summary>
/// <param name="item">The item to add.</param>
public new void Enqueue(T item)
{
while (Count >= limit)
{
Dequeue();
}
base.Enqueue(item);
}
}
}
You would use it like this:
LimitedQueue<int> numbers = new LimitedQueue<int>(5);
numbers.Enqueue(1);
numbers.Enqueue(2);
numbers.Enqueue(3);
numbers.Enqueue(4);
numbers.Enqueue(5);
numbers.Enqueue(6); // This will remove "1" from the list
// Here, "numbers" contains 2, 3, 4, 5, 6 (but not 1).
You can use a Queue with a fixed size. Just call .ToList() afterwards.
Fixed size queue which automatically dequeues old values upon new enques

ArgumentException in producer-consumer queue in C#

I have a producer/consumer queue as following but I am getting ArgumentWException.
Following is the code:
public class ProducerConsumer<T> where T : class
{
#region Private Variables
private Thread _workerThread;
private readonly Queue<T> _workQueue;
private object _enqueueItemLocker = new object();
private object _processRecordLocker = new object();
private readonly Action<T> _workCallbackAction;
private AutoResetEvent _workerWaitSignal;
#endregion
#region Constructor
public ProducerConsumer(Action<T> action)
{
_workQueue = new Queue<T>();
_workCallbackAction = action;
}
#endregion
#region Private Methods
private void ProcessRecord()
{
while (true)
{
T workItemToBeProcessed = default(T);
bool hasSomeWorkItem = false;
lock (_processRecordLocker)
{
hasSomeWorkItem = _workQueue.Count > 0;
if (hasSomeWorkItem)
{
workItemToBeProcessed = _workQueue.Dequeue();
if (workItemToBeProcessed == null)
{
return;
}
}
}
if (hasSomeWorkItem)
{
if (_workCallbackAction != null)
{
_workCallbackAction(workItemToBeProcessed);
}
}
else
{
_workerWaitSignal.WaitOne();
}
}
}
#endregion
#region Public Methods
/// <summary>
/// Enqueues work item in the queue.
/// </summary>
/// <param name="workItem">The work item.</param>
public void EnQueueWorkItem(T workItem)
{
lock (_enqueueItemLocker)
{
_workQueue.Enqueue(workItem);
if (_workerWaitSignal == null)
{
_workerWaitSignal = new AutoResetEvent(false);
}
_workerWaitSignal.Set();
}
}
/// <summary>
/// Stops the processer, releases wait handles.
/// </summary>
/// <param name="stopSignal">The stop signal.</param>
public void StopProcesser(AutoResetEvent stopSignal)
{
EnQueueWorkItem(null);
_workerThread.Join();
_workerWaitSignal.Close();
_workerWaitSignal = null;
if (stopSignal != null)
{
stopSignal.Set();
}
}
/// <summary>
/// Starts the processer, starts a new worker thread.
/// </summary>
public void StartProcesser()
{
if (_workerWaitSignal == null)
{
_workerWaitSignal = new AutoResetEvent(false);
}
_workerThread = new Thread(ProcessRecord) { IsBackground = true };
_workerThread.Start();
}
#endregion
}
Another class is:
public class Tester
{
private readonly ProducerConsumer<byte[]> _proConsumer;
public Tester()
{
_proConsumer = new ProducerConsumer<byte[]>(Display);
}
public void AddData(byte[] data)
{
try
{
_proConsumer.EnQueueWorkItem(recordData);
}
catch (NullReferenceException nre)
{
}
}
public void Start()
{
_proConsumer.StartProcesser();
}
private static object _recordLocker = new object();
private void Display(byte[] recordByteStream)
{
try
{
lock (_recordLocker)
{
Console.WriteLine("Done with data:" + BitConverter.ToInt32(recordByteStream, 0));
}
}
catch (Exception ex)
{
}
}
}
And my main function:
class Program
{
private static Tester _recorder;
static void Main(string[] args)
{
_recorder = new Tester();
_recorder.StartRecording();
for (int i = 0; i < 100000; i++)
{
_recorder.AddRecordData(BitConverter.GetBytes(i));
}
Console.Read();
}
}
Any idea why do I get the exception and what should I do to avoid that ?
Your class, in its current implementation, is not thread-safe. You're using two different objects for your Enqueue (lock (_enqueueItemLocker)) and Dequeue (lock (_processRecordLocker)) calls, which creates a race condition in your Queue<T>.
You need to lock the same object instance on both calls in order to safely use the queue.
If you're using .NET 4, I'd recommend either using ConcurrentQueue<T> or BlockingCollection<T> instead, as these would eliminate the need for the locks in your code, since they're thread-safe.

Categories

Resources