Greetings, I am trying to play some audio files without holding up the GUI. Below is a sample of the code:
if (audio)
{
if (ThreadPool.QueueUserWorkItem(new WaitCallback(CoordinateProc), fireResult))
{
}
else
{
MessageBox.Show("false");
}
}
if (audio)
{
if (ThreadPool.QueueUserWorkItem(new WaitCallback(FireProc), fireResult))
{
}
else
{
MessageBox.Show("false");
}
}
if (audio)
{
if (ThreadPool.QueueUserWorkItem(new WaitCallback(HitProc), fireResult))
{
}
else
{
MessageBox.Show("false");
}
}
The situation is the samples are not being played in order. some play before the other and I need to fix this so the samples are played one after another in order.
How do I implement this please?
Thank you.
EDIT: ThreadPool.QueueUserWorkItem(new WaitCallback(FireAttackProc), fireResult);
I have placed all my sound clips in FireAttackProc. What this does not do and I want is: wait until the thread stops running before starting a new thread so the samples dont overlap.
Why not just create one "WorkItem" and do everything there?
You can't guarrantee the order of execution of thread pool threads. Rather than that, as suggested by others, use a single thread to run the procs in order. Add the audio procs to a queue, run a single thread that pulls each proc off the queue in order and calls them. Use an event wait handle to signal the thread each time a proc is added to the queue.
An example (this doesn't completely implement the Dispose pattern... but you get the idea):
public class ConcurrentAudio : IDisposable
{
public ConcurrentAudio()
{
_queue = new ConcurrentQueue<WaitCallback>();
_waitHandle = new AutoResetEvent(false);
_disposed = false;
_thread = new Thread(RunAudioProcs);
_thread.IsBackground = true;
_thread.Name = "run-audio";
_thread.Start(null); // pass whatever "state" you need
}
public void AddAudio(WaitCallback proc)
{
_queue.Enqueue(proc);
_waitHandle.Set();
}
public void Dispose()
{
_disposed = true;
_thread.Join(1000); // don't feel like waiting forever
GC.SuppressFinalize(this);
}
private void RunAudioProcs(object state)
{
while (!_disposed)
{
try
{
WaitCallback proc = null;
if (_queue.TryDequeue(out proc))
proc(state);
else
_waitHandle.WaitOne();
}
catch (Exception x)
{
// Do something about the error...
Trace.WriteLine(string.Format("Error: {0}", x.Message), "error");
}
}
}
private ConcurrentQueue<WaitCallback> _queue;
private EventWaitHandle _waitHandle;
private bool _disposed;
private Thread _thread;
}
You should have a look at the BackgroundWorker option !
Related
I'm developing a windows service with .NET framework 4.0 and C#.
This service will open a socket to receive commands.
I have this socket listener class:
public class SocketListener
{
private System.Net.Sockets.TcpListener m_server;
public SQLServerSocketListener()
{
IPEndPoint ip = new IPEndPoint(IPAddress.Any, 5445);
m_server = new System.Net.Sockets.TcpListener(ip);
}
public void Start()
{
m_server.Start();
m_server.BeginAcceptTcpClient(new AsyncCallback(Callback), m_server);
}
public void Stop()
{
if (m_server != null)
m_server.Stop();
}
private void Callback(IAsyncResult ar)
{
if (!(m_server.Server.IsBound) ||
(m_server.Server == null))
return;
TcpClient client;
try
{
client = m_server.EndAcceptTcpClient(ar);
}
catch (ObjectDisposedException)
{
//Listener canceled
return;
}
DataHandler dataHandler = new DataHandler(client);
ThreadPool.QueueUserWorkItem(dataHandler.HandleClient, client);
m_server.BeginAcceptTcpClient(new AsyncCallback(Callback), m_server);
}
}
And this class to process the commands received through the socket:
class DataHandler
{
private bool m_disposed = false;
private TcpClient m_controlClient;
private IPEndPoint m_remoteEndPoint;
private string m_clientIP;
private NetworkStream m_controlStream;
private StreamReader m_controlReader;
public DataHandler(TcpClient client)
{
m_controlClient = client;
}
public void HandleClient(object obj)
{
m_remoteEndPoint = (IPEndPoint)m_controlClient.Client.RemoteEndPoint;
m_clientIP = m_remoteEndPoint.Address.ToString();
m_controlStream = m_controlClient.GetStream();
m_controlReader = new StreamReader(m_controlStream, true);
string line;
try
{
while (((line = m_controlReader.ReadLine()) != null) ||
(m_controlClient == null) ||
(!m_controlClient.Connected))
{
CommandHandler.ProcessCommand(line);
}
}
catch (Exception ex)
{
Console.WriteLine("CodeServerService.DataHandler error: {0}", ex.Message);
}
finally
{
Dispose();
}
}
}
And, the CommandHandler:
class CommandHandler
{
public static void ProcessCommand(string command, string connStringINICIC, string connStringTRZIC, byte codeLevel)
{
switch (command)
{
case "GetNewCodes<EOF>":
CodesIncremental.GetNewCodes();
break;
}
}
}
And CodesIncremental:
public class CodesIncremental
{
public static bool GetNewCodes()
{
[ ... ]
}
}
My problem is that I can receive GetNewCodes<EOF> command before the first one finish. So, I need to don't let GetNewCodes<EOF>runs if there is another GetNewCodes<EOF> running.
How can I don't let run CodesIncremental.GetNewCodes(); if this code its running in another thread?
I need something to discard the commands received while CodesIncremental.GetNewCodes(); is running.
In pseudo code:
If CodesIncremental.GetNewCodes(); is running do nothing.
This version does not block. CompareExchange ensures atomicity, so only one thread will swap the value of the _running variable, the rest of threads will just return inmediately.
public class CodesIncremental
{
static Int32 _running = 0;
public static bool GetNewCodes()
{
if (Interlocked.CompareExchange(ref _running, 1, 0) == 1)
return false;
try
{
// Do stuff...
return true;
}
finally
{
_running = 0;
}
}
}
A difference than monitors or other synchronization methods, there is little contention on this method, and it is quite faster.
Maybe like this using AutoResetEvent:
public class CodesIncremental
{
private AutoResetEvent _event = new AutoResetEvent(true);
public static bool GetNewCodes()
{
if(!_event.WaitOne(0))
return true; //is running
try
{
/*
actions in case if isn't running
*/
}
finally
{
_event.Set();
}
return false;
}
}
EDIT: Update to address the modification of the question.
A simple way is to use the Monitor.TryEnter and Monitor.Exit
Just call the ExecuteGetNewCodeCommand for the processing of your "GetNewCode" command.
object _myLock = new object();
void ExecuteGetNewCodeCommand( ArgType args)
{
bool result = false;
try
{
result = Monitor.TryEnter(_myLock); // This method returns immediately
if( !result) // check if the lock is acquired.
return;
// Execute your command code here
}
finally
{
if(result) // release the lock.
Monitor.Exit(_myLock);
}
}
Old answer (before the modification of the question):
Think about using a queue and a Thread Pool.
Every time you receive a new Command (including "GetNewCode") insert it into a queue. In addition, you will have a Thread Pool that will read requests from the queue and execute them.
If you are using only one thread in the Thread pool, or a dedicated thread for this type of commands (where there are other threads for other requests/commands in the queue/queus), then only one "GetNewCode" request will be running at the same time.
This way you can control the number of threads your server will run. Thus, also the resources your server uses.
If you just synchronize (via locks or other mechanism) then there are a performance penalties. And maybe a denial of service, if you reached a thread limit. Let's say for somehow the execution of a request is taking too long (Maybe a deadlock in your code). If you will not use a Thread pool, and will execute the commands/requests on the same thread the client connected to your, then your sever may hang.
Though, If you will synchronize the threads inside the thread pool, then the server will not hang. Maybe it will be really slow to execute the requests, but it will still run and work.
There is a default .Net ThreadPool implementation at MSDN.
Add a lock to your CodesIncremental Class:
public class CodesIncremental
{
private object m_threadLock = new object();
public static bool GetNewCodes()
{
lock(m_threadLock)
{
[ ... ]
}
}
}
http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx
This way when your GetNewCodes method is called the first time the 'lock' statement will get an exclusive lock on the 'm_threadLock' object and only release it when the execution leaves the lock block, if any other thread calls the methods while the first thread is still inside the lock block it will not be able to get an exclusive lock and execution will suspend until it can.
Update:
Since you want to discard other calls try this:
public class CodesIncremental
{
private static object m_threadLock = new object();
private static bool m_running = false;
public static bool GetNewCodes()
{
lock(m_threadLock)
{
if(m_running)
{
return;
}
m_running = true;
}
try
{
[ ... ]
}
finally
{
m_running = false;
}
}
}
there might be better ways but this should do the trick.
Update 2: Hadn't seen the static
Consider the following pattern:
private AutoResetEvent signal = new AutoResetEvent(false);
private void Work()
{
while (true)
{
Thread.Sleep(5000);
signal.Set();
//has a waiting thread definitely been signaled by now?
signal.Reset();
}
}
public void WaitForNextEvent()
{
signal.WaitOne();
}
The purpose of this pattern is to allow external consumers to wait for a certain event (e.g. - a message arriving). WaitForNextEvent is not called from within the class.
To give an example that should be familiar, consider System.Diagnostics.Process. It exposes an Exited event, but it also exposes a WaitForExit method, which allows the caller to wait synchronously until the process exits. this is what I am trying to achieve here.
The reason I need signal.Reset() is that if a thread calls WaitForNextEvent after signal.Set() has already been called (or in other words, if .Set was called when no threads were waiting), it returns immediately, as the event has already been previously signaled.
The question
Is it guaranteed that a thread calling WaitForNextEvent() will be signaled before signal.Reset() is called? If not, what are other solutions for implementing a WaitFor method?
Instead of using AutoResetEvent or ManualResetEvent, use this:
public sealed class Signaller
{
public void PulseAll()
{
lock (_lock)
{
Monitor.PulseAll(_lock);
}
}
public void Pulse()
{
lock (_lock)
{
Monitor.Pulse(_lock);
}
}
public void Wait()
{
Wait(Timeout.Infinite);
}
public bool Wait(int timeoutMilliseconds)
{
lock (_lock)
{
return Monitor.Wait(_lock, timeoutMilliseconds);
}
}
private readonly object _lock = new object();
}
Then change your code like so:
private Signaller signal = new Signaller();
private void Work()
{
while (true)
{
Thread.Sleep(5000);
signal.Pulse(); // Or signal.PulseAll() to signal ALL waiting threads.
}
}
public void WaitForNextEvent()
{
signal.Wait();
}
There is no guarantee. This:
AutoResetEvent flag = new AutoResetEvent(false);
new Thread(() =>
{
Thread.CurrentThread.Priority = ThreadPriority.Lowest;
Console.WriteLine("Work Item Started");
flag.WaitOne();
Console.WriteLine("Work Item Executed");
}).Start();
// For fast systems, you can help by occupying processors.
for (int ix = 0; ix < 2; ++ix)
{
new Thread(() => { while (true) ; }).Start();
}
Thread.Sleep(1000);
Console.WriteLine("Sleeped");
flag.Set();
// Decomment here to make it work
//Thread.Sleep(1000);
flag.Reset();
Console.WriteLine("Finished");
Console.ReadLine();
won't print "Work Item Executed" on my system. If I add a Thread.Sleep between the Set and the Reset it prints it. Note that this is very processor dependent, so you could have to create tons of threads to "fill" the CPUs. On my PC it's reproducible 50% of the times :-)
For the Exited:
readonly object mylock = new object();
then somewhere:
lock (mylock)
{
// Your code goes here
}
and the WaitForExit:
void WaitForExit()
{
lock (mylock) ;
// exited
}
void bool IsExited()
{
bool lockTacken = false;
try
{
Monitor.TryEnter(mylock, ref lockTacken);
}
finally
{
if (lockTacken)
{
Monitor.Exit(mylock);
}
}
return lockTacken;
}
Note that the lock construct isn't compatible with async/await (as aren't nearly all the locking primitives of .NET)
I would use TaskCompletionSources:
private volatile TaskCompletionSource<int> signal = new TaskCompletionSource<int>();
private void Work()
{
while (true)
{
Thread.Sleep(5000);
var oldSignal = signal;
signal = new TaskCompletionSource<int>()
//has a waiting thread definitely been signaled by now?
oldSignal.SetResult(0);
}
}
public void WaitForNextEvent()
{
signal.Task.Wait();
}
By the time that the code calls SetResult, no new code entering WaitForNextEvent can obtain the TaskCompletionSource that is being signalled.
I believe it is not guaranteed.
However, your logic flow is not understood by me. If your main thread Sets the signal, why should it wait until that signal reaches its destination? Wouldn't it be better to continue your "after signal set" logic in that thread which was waiting?
If you cannot do that, I recommend you to use second WaitHandle to signal the first thread that the second one has reveiced the signal. But I cannot see any pros of such a strategy.
I wonder how to abort my Thread after my function ends Thread.Abort();
My application running files and each file is opened is different thread
int _counter;
int _parallelThreads
_queue = new Queue();
public void transmit()
{
while (_counter < _parallelThreads)
{
lock (_queue)
{
string file = (string)_queue.Dequeue();
ThreadStart ts = delegate { processFile(file); };
Thread thread = new Thread(ts);
thread.IsBackground = true;
thread.Start();
_counter++;
}
}
}
private void processFile(string file)
{
WiresharkFile wf = new WiresharkFile(file, _selectedOutputDevice, 1);
wf.OnFinishPlayEvent += wf_OnFinishPlayEvent;
wf.sendBuffer();
}
and this is the event that my file finished
private void wf_OnFinishPlayEvent(MyClass class)
{
// here i want to abort my thread
}
The reason i want to abort my thread when it finished is because i think this is my memory lack reason in case i open a lot of parallels thread and run it over ond over (my application memory usage read more than 1 giga)
when you abort a thread, a lot of unexpected things can go wrong. particularly when you work with files. when i had to do that (for example, a "cancel" button) i used a litlle trick.
i had a flag IsCanceled on a scope both threads can see be set to true, and on the worker thread, every few statement, will check that flag and close all open files and end itself.
this might not work well for your situation, depending on wf.sendBuffer(); logic. let me know
Example:
private void processFile(string file)
{
WiresharkFile wf = new WiresharkFile(file, _selectedOutputDevice, 1);
wf.OnFinishPlayEvent += wf_OnFinishPlayEvent;
if(IsCanceled == false)
{
wf.sendBuffer();
}
}
and if the sendBuffer() method logic is too long, then
public void sendBuffer()
{
// some logic
if(IsCanceled)
{
// close open streams
return;
}
// some logic
}
as for the flag itself, a singleton class could do just fine for that, or a class all the other classes know
public class Singleton
{
private static Singleton instance;
private bool isCanceled;
private Singleton()
{
isCanceled = false;
}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
public bool IsCanceled
{
get
{
return isCanceled;
}
set
{
isCanceled = value;
}
}
}
notice that the singleton class is open to everyone, and you might want to use a class only known by the threads that needs to check it. that is something that depend on your security needs.
You should not abort the threads, threads will quit automatically when the code in it finishes. Maybe you just want to wait the thread to finish, after that do something else.
You can use an array to store the thread, and use Thread.Join() to wait all the threads end.
List<Thread> threadList = new List<Thread>();
public void transmit()
{
while (_counter < _parallelThreads)
{
lock (_queue)
{
string file = (string)_queue.Dequeue();
ThreadStart ts = delegate { processFile(file); };
Thread thread = new Thread(ts);
thread.IsBackground = true;
threadList.Add(thread); //add thread to list
thread.Start();
_counter++;
}
}
//wait threads to end
foreach(Thread t in threadList)
t.Join();
}
private void processFile(string file)
{
WiresharkFile wf = new WiresharkFile(file, _selectedOutputDevice, 1);
wf.OnFinishPlayEvent += wf_OnFinishPlayEvent;
wf.sendBuffer();
}
I am using following code.
public void runThread(){
if (System.Diagnostics.Process.GetProcessesByName("myThread").Length == 0)
{
Thread t = new Thread(new ThreadStart(go));
t.IsBackground = true;
t.Name = "myThread";
t.Start();
}
else
{
System.Diagnostics.Debug.WriteLine("myThreadis already Running.");
}
}
public void go()
{
//My work goes here
}
I am calling runThread() function many time but i want thread only start when thread is not running. How is it possible?
GetProcessesByName will not look for threads in your application but for processes in your machine. In fact there is no good way to get query for the threads in your own application (a matter aside is writing a debugger).
For what you want you could create a wrapper class for your threads in such way that you could query if they are running. Or keep track of the threads yourself by other means.
You could also consider to have a Lazy<Thread> field that will be initialized when needed, and you can query to see if the thread is till alive. After testing Lazy<Thread> is not a good idea.
Derived from Simon's answer:
private int running;
public void runThread()
{
if (Interlocked.CompareExchange(ref running, 1, 0) == 0)
{
Thread t = new Thread
(
() =>
{
try
{
go();
}
catch
{
//Without the catch any exceptions will be unhandled
//(Maybe that's what you want, maybe not*)
}
finally
{
//Regardless of exceptions, we need this to happen:
running = 0;
}
}
);
t.IsBackground = true;
t.Name = "myThread";
t.Start();
}
else
{
System.Diagnostics.Debug.WriteLine("myThreadis already Running.");
}
}
public void go()
{
//My work goes here
}
*: Gotta catch'em all
Wajid and Segey are right. You could just have a Thread field. Allow me to provide the example:
private Thread _thread;
public void runThread()
{
var thread = _thread;
//Prevent optimization from not using the local variable
Thread.MemoryBarrier();
if
(
thread == null ||
thread.ThreadState == System.Threading.ThreadState.Stopped
)
{
var newThread = new Thread(go);
newThread.IsBackground = true;
newThread.Name = "myThread";
newThread.Start();
//Prevent optimization from setting the field before calling Start
Thread.MemoryBarrier();
_thread = newThread;
}
else
{
System.Diagnostics.Debug.WriteLine("myThreadis already Running.");
}
}
public void go()
{
//My work goes here
}
Note: It is better to use the first alternative (the one derived from Simon's answer) because it is thread-safe. That is, if there are various thread calling the method runThread simultaneously there is no risk of more than one thread being created.
One easy way is that you could have a flag that indicates if it's running or not. You maybe have to use some lock if it's some conflicts.
public static bool isThreadRunning = false;
public void runThread()
{
if (!isThreadRunning)
{
Thread t = new Thread(new ThreadStart(go));
t.IsBackground = true;
t.Name = "myThread";
t.Start();
}
else
{
System.Diagnostics.Debug.WriteLine("myThreadis already Running.");
}
}
public void go()
{
isThreadRunning = true;
//My work goes here
isThreadRunning = false;
}
You can use Thread.IsAlive to check whether prevoius thread is running or not.This is to give the thread status.You can put this check before mythread.Start().
Do you create the thread only in run thread method? If it is so hold it as field of the class that holds runThread method and ask t.IsAlive.
Maybe this can help you
static bool isRunning = false;
public void RunThread(){
if (!isRunning)
{
Thread t = new Thread(()=> { go(); isRunning = true;});
t.IsBackground = true;
t.Name = "myThread";
t.Start();
}
else
{
System.Diagnostics.Debug.WriteLine("myThread is already Running.");
}
}
public void go()
{
//My work goes here
}
I have a class running the Producer-Consumer model like this:
public class SyncEvents
{
public bool waiting;
public SyncEvents()
{
waiting = true;
}
}
public class Producer
{
private readonly Queue<Delegate> _queue;
private SyncEvents _sync;
private Object _waitAck;
public Producer(Queue<Delegate> q, SyncEvents sync, Object obj)
{
_queue = q;
_sync = sync;
_waitAck = obj;
}
public void ThreadRun()
{
lock (_sync)
{
while (true)
{
Monitor.Wait(_sync, 0);
if (_queue.Count > 0)
{
_sync.waiting = false;
}
else
{
_sync.waiting = true;
lock (_waitAck)
{
Monitor.Pulse(_waitAck);
}
}
Monitor.Pulse(_sync);
}
}
}
}
public class Consumer
{
private readonly Queue<Delegate> _queue;
private SyncEvents _sync;
private int count = 0;
public Consumer(Queue<Delegate> q, SyncEvents sync)
{
_queue = q;
_sync = sync;
}
public void ThreadRun()
{
lock (_sync)
{
while (true)
{
while (_queue.Count == 0)
{
Monitor.Wait(_sync);
}
Delegate query = _queue.Dequeue();
query.DynamicInvoke(null);
count++;
Monitor.Pulse(_sync);
}
}
}
}
/// <summary>
/// Act as a consumer to the queries produced by the DataGridViewCustomCell
/// </summary>
public class QueryThread
{
private SyncEvents _syncEvents = new SyncEvents();
private Object waitAck = new Object();
private Queue<Delegate> _queryQueue = new Queue<Delegate>();
Producer queryProducer;
Consumer queryConsumer;
public QueryThread()
{
queryProducer = new Producer(_queryQueue, _syncEvents, waitAck);
queryConsumer = new Consumer(_queryQueue, _syncEvents);
Thread producerThread = new Thread(queryProducer.ThreadRun);
Thread consumerThread = new Thread(queryConsumer.ThreadRun);
producerThread.IsBackground = true;
consumerThread.IsBackground = true;
producerThread.Start();
consumerThread.Start();
}
public bool isQueueEmpty()
{
return _syncEvents.waiting;
}
public void wait()
{
lock (waitAck)
{
while (_queryQueue.Count > 0)
{
Monitor.Wait(waitAck);
}
}
}
public void Enqueue(Delegate item)
{
_queryQueue.Enqueue(item);
}
}
The code run smoothly but the wait() function.
In some case I want to wait until all the function in the queue were finished running so I made the wait() function.
The producer will fire the waitAck pulse at suitable time.
However, when the line "Monitor.Wait(waitAck);" is ran in the wait() function, all thread stop, includeing the producer and consumer thread.
Why would this happen and how can I solve it? thanks!
It seems very unlikely that all the threads will actually stop, although I should point out that to avoid false wake-ups you should probably have a while loop instead of an if statement:
lock (waitAck)
{
while(queryProducer.secondQueue.Count > 0)
{
Monitor.Wait(waitAck);
}
}
The fact that you're calling Monitor.Wait means that waitAck should be released so it shouldn't prevent the consumer threads from locking...
Could you give more information about the way in which the producer/consumer threads are "stopping"? Does it look like they've just deadlocked?
Is your producer using Notify or NotifyAll? You've got an extra waiting thread now, so if you only use Notify it's only going to release a single thread... it's hard to see whether or not that's a problem without the details of your Producer and Consumer classes.
If you could show a short but complete program to demonstrate the problem, that would help.
EDIT: Okay, now you've posted the code I can see a number of issues:
Having so many public variables is a recipe for disaster. Your classes should encapsulate their functionality so that other code doesn't have to go poking around for implementation bits and pieces. (For example, your calling code here really shouldn't have access to the queue.)
You're adding items directly to the second queue, which means you can't efficiently wake up the producer to add them to the first queue. Why do you even have multiple queues?
You're always waiting on _sync in the producer thread... why? What's going to notify it to start with? Generally speaking the producer thread shouldn't have to wait, unless you have a bounded buffer
You have a static variable (_waitAck) which is being overwritten every time you create a new instance. That's a bad idea.
You also haven't shown your SyncEvents class - is that meant to be doing anything interesting?
To be honest, it seems like you've got quite a strange design - you may well be best starting again from scratch. Try to encapsulate the whole producer/consumer queue in a single class, which has Produce and Consume methods, as well as WaitForEmpty (or something like that). I think you'll find the synchronization logic a lot easier that way.
Here is my take on your code:
public class ProducerConsumer
{
private ManualResetEvent _ready;
private Queue<Delegate> _queue;
private Thread _consumerService;
private static Object _sync = new Object();
public ProducerConsumer(Queue<Delegate> queue)
{
lock (_sync)
{
// Note: I would recommend that you don't even
// bother with taking in a queue. You should be able
// to just instantiate a new Queue<Delegate>()
// and use it when you Enqueue. There is nothing that
// you really need to pass into the constructor.
_queue = queue;
_ready = new ManualResetEvent(false);
_consumerService = new Thread(Run);
_consumerService.IsBackground = true;
_consumerService.Start();
}
}
public override void Enqueue(Delegate value)
{
lock (_sync)
{
_queue.Enqueue(value);
_ready.Set();
}
}
// The consumer blocks until the producer puts something in the queue.
private void Run()
{
Delegate query;
try
{
while (true)
{
_ready.WaitOne();
lock (_sync)
{
if (_queue.Count > 0)
{
query = _queue.Dequeue();
query.DynamicInvoke(null);
}
else
{
_ready.Reset();
continue;
}
}
}
}
catch (ThreadInterruptedException)
{
_queue.Clear();
return;
}
}
protected override void Dispose(bool disposing)
{
lock (_sync)
{
if (_consumerService != null)
{
_consumerService.Interrupt();
}
}
base.Dispose(disposing);
}
}
I'm not exactly sure what you're trying to achieve with the wait function... I'm assuming you're trying to put some type of a limit to the number of items that can be queued. In that case simply throw an exception or return a failure signal when you have too many items in the queue, the client that is calling Enqueue will keep retrying until the queue can take more items. Taking an optimistic approach will save you a LOT of headaches and it simply helps you get rid of a lot of complex logic.
If you REALLY want to have the wait in there, then I can probably help you figure out a better approach. Let me know what are you trying to achieve with the wait and I'll help you out.
Note: I took this code from one of my projects, modified it a little and posted it here... there might be some minor syntax errors, but the logic should be correct.
UPDATE: Based on your comments I made some modifications: I added another ManualResetEvent to the class, so when you call BlockQueue() it gives you an event which you can wait on and sets a flag to stop the Enqueue function from queuing more elements. Once all the queries in the queue are serviced, the flag is set to true and the _wait event is set so whoever is waiting on it gets the signal.
public class ProducerConsumer
{
private bool _canEnqueue;
private ManualResetEvent _ready;
private Queue<Delegate> _queue;
private Thread _consumerService;
private static Object _sync = new Object();
private static ManualResetEvent _wait = new ManualResetEvent(false);
public ProducerConsumer()
{
lock (_sync)
{
_queue = new Queue<Delegate> _queue;
_canEnqueue = true;
_ready = new ManualResetEvent(false);
_consumerService = new Thread(Run);
_consumerService.IsBackground = true;
_consumerService.Start();
}
}
public bool Enqueue(Delegate value)
{
lock (_sync)
{
// Don't allow anybody to enqueue
if( _canEnqueue )
{
_queue.Enqueue(value);
_ready.Set();
return true;
}
}
// Whoever is calling Enqueue should try again later.
return false;
}
// The consumer blocks until the producer puts something in the queue.
private void Run()
{
try
{
while (true)
{
// Wait for a query to be enqueued
_ready.WaitOne();
// Process the query
lock (_sync)
{
if (_queue.Count > 0)
{
Delegate query = _queue.Dequeue();
query.DynamicInvoke(null);
}
else
{
_canEnqueue = true;
_ready.Reset();
_wait.Set();
continue;
}
}
}
}
catch (ThreadInterruptedException)
{
_queue.Clear();
return;
}
}
// Block your queue from enqueuing, return null
// if the queue is already empty.
public ManualResetEvent BlockQueue()
{
lock(_sync)
{
if( _queue.Count > 0 )
{
_canEnqueue = false;
_wait.Reset();
}
else
{
// You need to tell the caller that they can't
// block your queue while it's empty. The caller
// should check if the result is null before calling
// WaitOne().
return null;
}
}
return _wait;
}
protected override void Dispose(bool disposing)
{
lock (_sync)
{
if (_consumerService != null)
{
_consumerService.Interrupt();
// Set wait when you're disposing the queue
// so that nobody is left with a lingering wait.
_wait.Set();
}
}
base.Dispose(disposing);
}
}