I hope to get some conceptual advice for some kind of producer/consumer scenario.
Let's say I have a "producer" thread, that creates some integer or double value, normally in a rather periodic way, but there may be arbitrary delays in between.
Now there are several "consumer" threads, that all should start doing something with this value in parallel as soon as the value arrives.
Each one of those "consumer" threads may need another amount of time to fulfill its task. Once a "consumer" is ready, it should wait for the next produced value.
However, if it took too long to finish the task with the previous value the consumer should continue immediately with whatever value is due (if any). I don't need a queue, values may be skipped if several arrive while the consumers are working. So it's solely important if there is a new value and which is the latest if any consumer is ready to consume the next value.
Is there any other viable way than having one AutoResetEvent/ManualResetEvent per "consumer"?
The specific solution should work in Unity3D, so it requires Mono2.
Edit: Since I'm interested in a conceptual advice it's hard to come up with some source code. I hope the following will illustrate the problem a bit.
int data = 0;
producer = new Timer(20, OnTimer);
consumer1 = new Consumer(OnConsume1);
consumer2 = new Consumer(OnConsume2);
OnTimer()
{
data = data + 20;
TriggerConsumers();
}
OnConsume1()
{
while (running)
{
WaitForData();
// do something with data
Thread.Sleep(10);
}
}
OnConsume2()
{
while (running)
{
WaitForData();
// do something with data
Thread.Sleep(30);
}
}
There is the producer, that creates a new value every 20ms. Then there are two consumers (might be more later) that wait for the value and do something with it. One consumer takes 10ms, the other 30ms. This should lead to the following timeline if producer/consumers start at the same time:
20 data = 20 => OnConsume1, OnConsume2 run with data = 20 30 OnConsume1 will wait for data, OnConsume2 is "working" 40 data = 40 => OnConsume1 run with data = 40, OnConsume2 still "working" 50 OnConsume1 will wait, OnConsume2 will run with data = 40 60 data = 60 => OnConsume1 run with data = 60, OnConsume2 is "working" 70 OnConsume1 will wait, OnConsume2 still "working" 80 data = 80 => OnConsume1 => data = 80, OnConsume2 should also run with 80 (neglecting the race that it might work with 60)
Sounds like you'll want a stack / queue if you want more than a single value available, with a max depth. Or a single nullable value, such as.
public int? value;
OnConsume1()
{
while (running)
{
int myValue;
if(value != null) // or value.HasValue
{
myValue = value.Value; // or (int)value
value = null; // let other consumers know the value is being processed
// do something with data
}
Thread.Sleep(10);
}
}
You'll want to use the lock
functionality of C# to keep only one thread modifying the value(s) at once.
If you want to use a thread safe container, check out these.