I have an application in C# which generates a series of images in the form of movie clip, which contains two methods. Each method generates a series of images (frames per second) which will display to my outputs (PictureBox_1 and PictureBox_2 accordingly).
My question is how can I mix this these series of images from two methods with each other randomly and instead of playing each thread separately I run the third thread which is the randomly mixing of two other threads?
For example the output are as follow:
Thread one: bmp1, bmp1, bmp1, …
Thread two: bmp2, bmp2, bmp2, …
Thread three; bmp1, bmp1, bmp2, bmp1, bmp2, bmp2, bmp2, bmp1, …
The obvious solution would be to push generated images from both threads into a central Queue which is read by the third thread.
To notify the third thread about new pushed images you can use AutoResetEvent
.
OK a quick example for you.
class Program
{
static ConcurrentQueue<int> _centralQueue = new ConcurrentQueue<int>();
static AutoResetEvent _signaller = new AutoResetEvent(false);
static void Main(string[] args)
{
Task.Factory.StartNew(() => Producer1Thread());
Task.Factory.StartNew(() => Producer2Thread());
var neverEndingConsumer = Task.Factory.StartNew(() => ConsumerThread());
neverEndingConsumer.Wait();
}
static void Producer1Thread()
{
for (int i=2000; i<3000; i++)
{
_centralQueue.Enqueue(i);
_signaller.Set();
Thread.Sleep(8);
}
}
static void Producer2Thread()
{
for (int i = 0; i < 1000; i++)
{
_centralQueue.Enqueue(i);
_signaller.Set();
Thread.Sleep(10);
}
}
static void ConsumerThread()
{
while (true)
{
if (_centralQueue.IsEmpty)
{
_signaller.WaitOne();
}
int number;
if (_centralQueue.TryDequeue(out number))
{
Console.WriteLine(number);
}
}
}
}
First two threads produce numbers, one thread range 1-1000 other in 2000-3000. Third thread reads the produced results.
Ofcourse instead of int
you would use your Image class.
Please note that the above code does neverEndingConsumer.Wait();
only for testing purposes. You don't want this in your code as it blocks forever.
Another hint: If you access the picturebox from the consumer thread don't forget to use Invoke to marshal the UI access to the GUI thread.
You may generate yout images with a ThreadPool WorkerThread. The sequence you feed in the ThreadPool-Thread must not the same as they processed.
This seems a bit randomly...
Not tested or compiled, is just Pseudo-Code:
QueueUserWorkItem(()=>
{
// code that generates the image
var img = GenerateImage();
// set image to PictureBox via SynchronizationContext of the UI-Thread
formSyncContext.Send(()=> pb.Image = img);
}