Process List<T> member when added in a separate thread
So first here is some pseudo code of what I want to improve.
public List<ProcessData> Processes; System.Threading.Thread ProcessThread; void ProcessLoop() { while (true) { for (int i = 0; i < Processes.Count; i++) { if (HasPriority(Processes[i])) { Process(Processes[i]); } } System.Threading.Thread.Sleep(1000); } } void AddProcessData(ProcessData pd) { Processes.Add(pd); if (Suspended(ProcessThread)) Resume(ProcessThread); } void Startup() { ProcessThread = new System.Threading.Thread(ProcessLoop); ProcessThread.Start(); }
So what I want to do is replace the 'Sleep' with code that will suspend the thread or have it wait until something is added to the list and then resume it. I also need it to be thread safe开发者_StackOverflow社区 of course.
What you want is an event.
EDIT: to make it thread-safe.
public List<ProcessData> Processes;
System.Threading.Thread ProcessThread;
System.Threading.AutoResetEvent ProcessesChangedEvent = new System.Threading.AutoResetEvent(false);
void ProcessLoop()
{
while (true)
{
// You might want to copy out the entire list as an array instead
// if HasPriority or Process take a long time.
lock (Processes)
{
for (int i = 0; i < Processes.Count; i++)
{
if (HasPriority(Processes[i]))
{
Process(Processes[i]);
}
}
}
ProcessesChangedEvent.WaitOne(...); // timeout?
}
}
void AddProcessData(ProcessData pd)
{
lock (Processes)
Processes.Add(pd);
ProcessesChangedEvent.Set(); // you can also use Monitor.PulseAll/Wait
}
void Startup()
{
ProcessThread = new System.Threading.Thread(ProcessLoop);
ProcessThread.Start();
}
In your case best desicion is to use one of next classes: ManualResetEvent or AutoResetEvent
What you really need is a BlockingQueue. You can find a quality implementation here. Or if you are using v4 of the .NET Framework then you can use the builtin BlockingCollection class. Notice how much easier the code is when using this type of data structure.
public class YourClass
{
private BlockingQueue<ProcessData> m_Queue = new BlockingQueue<ProcessData();
private void ProcessLoop()
{
while (true)
{
ProcessData item = m_Queue.Dequeue();
if (HasPriority(item))
{
Process(item);
}
}
}
public void AddProcessData(ProcessData item)
{
m_Queue.Enqueue(item);
}
public void Startup()
{
var thread = new Thread(() => { ProcessLoop(); });
thread.Start();
}
}
Get to know the RX framework from Microsoft. http://rxwiki.wikidot.com/start there you can get an event every x seconds and do something then. no need to start threads at all.
or use a timer, and make the check in the elapsed event.
Just in case you really need to process the data only once, here is some code
public Queue<ProcessData> Processes;
System.Threading.Thread[] ProcessThreads = new System.Threading.Thread[5];
System.Threading.Semaphore semToDo = new System.Threading.Semaphore(0,int.MaxValue);
void ProcessLoop()
{
ProcessData pd;
while (true)
{
semToDo.WaitOne();
lock (Processes)
{
pd = Processes.Dequeue();
}
Process(pd);
}
}
private void Process(ProcessData processData)
{
throw new NotImplementedException();
}
void AddProcessData(ProcessData pd)
{
lock (Processes)
{
Processes.Enqueue(pd);
}
semToDo.Release();
}
void Startup()
{
//you can even have multiple worker threads now!
for(int i = 0; i < 5; i++)
ProcessThreads[i] = new System.Threading.Thread(ProcessLoop);
foreach (System.Threading.Thread t in ProcessThreads)
{
t.Start();
}
}
精彩评论