I know of course that I can not draw onto the same Graphics object from different threads, but is it also true that I can not draw to different Graphics objects in different threads?
Consider the following console program:
class Program
{
static ThreadDrawer[] drawers;
static void Main(string[] args)
{
int numThreads = 8;
drawers = new ThreadDrawer[numThreads];
for (int i = 0; i < numThreads; i++)
{
drawers[i] = new ThreadDrawer();
drawers[i].Start();
}
for (int i = 0; i < numThreads; i++)
{
drawers[i].Wait();
}
Console.WriteLine("Complete.");
Console.ReadKey();
}
class ThreadDrawer
{
private Thread thread;
private AutoResetEvent resetEvent;
public ThreadDrawer()
{
thread = new Thread(DrawRandomCircles);
resetEvent = new AutoResetEvent(false);
}
public void Start()
{
thread.Start();
}
public void Wait()
{
resetEvent.WaitOne();
}
public void DrawRandomCircles()
{
Random r = new Random(Environment.TickCount);
using (Bitmap b = new Bitmap(1000, 1000))
using (Graphics g = Graphics.FromImage(b))
{
for (int i = 0; i < 100000; i++)
{
g.DrawEllipse(Pens.Red, new Rectangle(r.Next(1000), r.Next(1000), 200, 200));
}
}
resetEvent.Set();
}
}
}
The program creates a Bitmap in each thread and proceeds to draw random ellipses on it using a Graphics object, also generated per thread from the Bitmap.
Due to a requirement to build for .net2 the multithreading is implemented using Threads and AutoResetEvents instead of TPL.
The program executes without throwing an exception, but it executes serially. Using n threads multiplies execution time by n and it is clear to see using the task manager that only one core is being used.
Important to take note that none of this is tied to any UI element.
What is going on here? Is the Graphics object locking on a static object?
Here's a screen-shot of the concurrency analyzer I used to see what's going on with these threads:
Yes, you can see lots of red (blocking) with flecks of green (execution). The threads are taking turns entering a critical section that's acquired inside the internal GpGraphics::RenderDrawPath() function. The larger blobs of green is where the program actually drew the lines (I replaced DrawEllipse with DrawRectangle and got rid of the Random call).
There is some concurrency, you can for example see the RenderDrawPath() call being overlapped by the code that renders the anti-aliased lines, overall cpu load is around 35%. But there isn't much of it.
Nothing you can do about it of course. You get ahead by overlapping the logic in your own program to decide what to draw with the GDI+ calls. Which will normally happen, the test is too synthetic.
It seems like locking happens in unmanaged code, inside GDI+ library (unfortunately, this behavior is not mentioned in official docs).
Similar question: Parallelizing GDI+ Image Resizing .net
I'm not 100% sure.. but yes, there is a private static locking object in the Graphics class. It appears to be locked only from GetHalftonePalette, which in turn, is called whenever a Bitmap is initialized within the Graphics object. It would appear that this could be the cause of contention.
(Note: Initial findings after 5 minutes of using ILSpy.. not very in-depth)
Related
This is a short one that I have been unable to google a clear answer for.
Basically, I’m working with pixels but I want to put it on a second thread so UI and everything runs during expensive operations.
Are Vector4s, which are implicitly convertable to and from Color, allowed on other threads even though Unity isn’t thread safe?
Basically, how would I go about doing color operations without Color struct or Vector4s (if those don’t work either)?
In short: YES! (as long as you don't read/write them at the same time of course).
In long:
Only those parts that directly require or influence the Scene itself are not usable from any other threads than the Unity "main" thread. Unity immediately blocks it and shows a warning. So what you can not do is e.g. setting or getting Transform properties, trying to access .gameObject on any Component, anything related to Texture2D, stuff like GetComponent, Find etc.
structs, however, like Vector4, Color, Quaternion etc are just basic data containers holding some values and doing some pure mathematical operations on them ... they can be used in any background thread in order to process them.
Even your own MonoBehaviour can possibly be used in background threads (you just pass in a reference) as long as you access only those fields and only call those methods, that - again - don't immediately require or influence the Scene.
However, they are not "thread-safe" themselves, meaning there is no lock going on. So of course you have to assure yourself that your threads (Unity main thread and background thread(s)) have exclusive access to your values, meaning only exactly one thread may be reading and writing at the same time.
Something like this is completely valid:
private IEnumerator Start ()
{
Debug.Log("MainThread: Let's get some colors");
var stopWatch = new Stopwatch();
stopWatch.Restart();
var thread = new Thread(ColorThread);
thread.Start();
while (!ColorsReceived())
{
Debug.Log("MainThread: ... still waiting ...");
yield return new WaitForSeconds(0.5f);
}
lock(_lock)
{
Debug.Log($"MainThread: Got {colors.Length} colors after {stopWatch.ElapsedMilliseconds / 1000f} seconds");
}
}
private bool ColorsReceived()
{
lock(_lock)
{
return colors != null;
}
}
private void ColorThread()
{
Debug.Log("BackgroundThread: Started generating colors");
var output = new Color[1000];
var random = new System.Random();
for(var i = 0; i < output.Length;i++)
{
output[i] = new Color32((byte) random.Next(0, 256), (byte) random.Next(0, 256), (byte) random.Next(0, 256), (byte)random.Next(0,256));
}
// Do some havy stuff
Thread.Sleep(3000);
lock(_lock)
{
colors = output;
}
Debug.Log("BackgroundThread: Finished generating colors");
}
=>
MainThread: Lets's get some colors
MainThread: ... still waiting ...
BackgroundThread: Started generating colors
MainThread: ... still waiting ...
MainThread: ... still waiting ...
MainThread: ... still waiting ...
MainThread: ... still waiting ...
BackgroundThread: Finished generating colors
MainThread: Got 1000 colors after 3.19 seconds
In my custom control am using nearly 1000 series with 100 points each which results in delay in drawing and even after drawn also it takes some amount time to be responsive.
Am even using Begin and End update before loading points. But no use.
I have replicated the same in a simple sample by drawing a line in a loop, which also goes to unresponsive state.
Is there any solution to overcome this.
public Form2()
{
InitializeComponent();
ControlExt controlExt = new ControlExt();
this.Controls.Add(controlExt);
}
public class ControlExt : Control
{
public ControlExt()
{
Height = 500;
Width = 1000;
}
protected override void OnPaint(PaintEventArgs e)
{
for (int i = 0; i < 1000; i++)
{
for (int j = 0; j < 100; j++)
{
using (var pen = new Pen(Color.Red, 2))
{
e.Graphics.DrawLine(pen, 400, 200, 300, 100);
}
}
}
}
}
Drawing lines is done on the main thread, and can be quite inefficient when there is many lines. Winforms is based on GDI, and this uses Immediate Mode rendering. This has a tendency to scale poorly since the processor have to send all the commands to the graphics device each frame.
The typical solution is to use fewer drawing commands, and therefore suffer less overhead. For example:
Use DrawLines if the line segments are connected in strips.
Create a graphics path for all the lines and use DrawPath
Create a Bitmap, draw to this image on a background thread, and then use DrawImage in the UI.
I have this code, and have a function named STARTWORK(int THREADNR) which cannot be called by 2 threads. Basically all the work of my program is contained in this function, where in the WORKVOID1() and WORKVOID2() i use separate for() functions to run through the data, and the for() function is split in half so that the 2 functions cover half-half of the data to be much faster and work on multicore processor.The problem is that if there is only the main thread, it works like a charm, but if i try to split the STARTWORK() into 2 parts in WORKVOID1() and WORKVOID2() each in multiple threads it doesn't work, so please help me fix it.
public void OPTIMIZATION_ITERATION()
{
Thread WORK = new Thread(WORKVOID);
WORK.Name = "T1";
WORK.Start();
Thread WORK2 = new Thread(WORKVOID2);
WORK2.Name = "T2";
WORK2.Start();
}
public void WORKVOID()
{
for (ALPHA = 0.001; ALPHA <= 0.5; ALPHA += 0.001)
STARTWORK(1);
}
public void WORKVOID2()
{
for (ALPHA = 0.5; ALPHA <= 1; ALPHA += 0.001)
STARTWORK(2);
}
public void STARTWORK(int THREAD)
{
//.......bunch of calculations then it writes it to file
System.IO.StreamWriter WRITE = new System.IO.StreamWriter("OUTPUT_T"+THREAD+".txt", true);
WRITE.BaseStream.Seek(0, SeekOrigin.End);
WRITE.WriteLine(/*..calculations are written to file..*/);
WRITE.Close();
WRITE.Dispose();
}
The STARTWORK(int THREADNR) contains a parameter which will assign a number that will write the data to file so that the 2 will have different filenames, while ALPHA is a global double variable.
if your working in c# you might want to try this.
public void OPTIMIZATION_ITERATION()
{
Thread WORK = new Thread(new ThreadStart(WORKVOID));
WORK.Name = "T1";
WORK.Start();
Thread WORK2 = new Thread(new ThreadStart(WORKVOID2));
WORK2.Name = "T2";
WORK2.Start();
}
public void WORKVOID()
{
for (ALPHA = 0.001; ALPHA <= 0.5; ALPHA += 0.001)
STARTWORK(1);
}
public void WORKVOID2()
{
for (ALPHA = 0.5; ALPHA <= 1; ALPHA += 0.001)
STARTWORK(2);
}
I think the problem is ALPHA. As soon as you start the second thread you set it equal to the condition that the first thread is looking for (ALPHA <= .5), then the first thread increments ALPHA by .001. The net result is that the first thread is highly unlikely to write anything to the file (maybe one line, depending on timing).
Beyond that, I don't really see the point of trying to to do this in parallel, if you are writing to the same disk, it's not going to help anything. If the calculations you are doing are CPU intense, then it might be a better approach to make the calculations parallel and then write everything to disk after it's done, or in chunks if memory is an issue.
Global variables such as ALPHA cannot be used safely in multi-threaded contexts. This is because both threads are allowed to read/write at the exact same time which causes a race condition. I recommend you change your work methods to accept a double parameter. That way, each method would be using a local variable instead of a global shared variable.
I need to make a console application that uses Kinect, with Kinect SDK and c#. Since it's a console application, I've found polling to be the best way to retrieve the frames I need to process. I'll need to retrieve frames from the depth camera and the rgb camera, do some processing on then in separate threads (one for the depth image and one for the rgb image), and give an output to the user for each of the two processed frames. The way I've been thinking about doing this is the following:
1 - create 2 threads, the first is on the method that polls the rgb camera and do the processing, the second is on the method that polls the depth camera and do the processing
2 - Start the threads
3 - enter a while some stop condition loop
4 - check separately if each thread is alive, if not, create them again and start them again
I've made a test program that follows those steps and it works, but I'm not sure it's the best way of doing it. My test program is
class Program
{
private static ClassExecutioner Executioner;
private static Class1 Cls;
static void Main(string[] args)
{
Executioner = new ClassExecutioner();
Cls = new Class1();
Thread fThread = new Thread(new ThreadStart(processA));
Thread sThread = new Thread(new ThreadStart(processB));
fThread.Start();
sThread.Start();
while (true)
{
if (!fThread.IsAlive)
{
fThread = new Thread(new ThreadStart(processA));
fThread.Start();
}
if (!sThread.IsAlive)
{
sThread = new Thread(new ThreadStart(processB));
sThread.Start();
}
}
}
static void processA()
{
String frameA = Cls.pollA();
Executioner.CallA(frameA);
}
static void processB()
{
String frameB = Cls.pollB();
Executioner.CallB(frameB);
}
}
Class 1 methods represent the polling of the cameras on kinect
class Class1
{
private int a;
private int b;
public Class1()
{
a = 0;
b = 0;
}
public String pollA()
{
String frame = "this is " + a % 100;
a++;
return frame;
}
public String pollB()
{
String frame = "I am " + b % 100;
b++;
return frame;
}
}
Executioner represents the methods that process the frames obtained from Kinect
class ClassExecutioner
{
public ClassExecutioner()
{
}
public void CallA(String frameA)
{
Random rand = new Random();
int time = rand.Next() % 1000000000;
//'processing' - wait some time
for (int i = 0; i < time; i++)
{
}
// finishes the processing of the 'frame' from stream A
Console.WriteLine(frameA);
}
public void CallB(String frameB)
{
Random rand = new Random();
int time = rand.Next() % 1000000000;
// 'processing' - wait some time
for (int i = 0; i < time; i++)
{
}
// finishes the processing of the 'frame' from stream B
Console.WriteLine(frameB);
}
}
The program is very simple but ilustrates well what I want to do with the Kinect streams. The problem is, I'm not sure this is the best way of doing it or even if this is gonna work at all on a practical, Kinect application. Keep in mind that, for now, each processing (depth and rgb) doesn't need information from the other.
Thanks in advance!
It might be cool to look into the ReactiveExtensions framework. It deals with async event streams very cleanly.
You can write LINQ against the data sources and do very interesting composable operations.
http://msdn.microsoft.com/en-us/data/gg577609.aspx
You basically would have two IEnumerable sequences (the things that loop infinitely) that yield out the frame at the given interval. You can then "query" these sequences using Rx. RX handles all the complicated threading issues for you and makes your consumer code clean and simple.
To be clear, you don't want to be creating new threads each time. You can create two infinite enumerables that each run on their own thread and yield out the result on each iteration. That way they don't even "die"
I have boiled down an issue I'm seeing in one of my applications to an incredibly simple reproduction sample. I need to know if there's something amiss or something I'm missing.
Anyway, below is the code. The behavior is that the code runs and steadily grows in memory until it crashes with an OutOfMemoryException. That takes a while, but the behavior is that objects are being allocated and are not being garbage collected.
I've taken memory dumps and ran !gcroot on some things as well as used ANTS to figure out what the problem is, but I've been at it for a while and need some new eyes.
This reproduction sample is a simple console application that creates a Canvas and adds a Line to it. It does this continually. This is all the code does. It sleeps every now and again to ensure that the CPU is not so taxed that your system is unresponsive (and to ensure there's no weirdness with the GC not being able to run).
Anyone have any thoughts? I've tried this with .NET 3.0 only, .NET 3.5 and also .NET 3.5 SP1 and the same behavior occurred in all three environments.
Also note that I've put this code in a WPF application project as well and triggered the code in a button click and it occurs there too.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows;
namespace SimplestReproSample
{
class Program
{
[STAThread]
static void Main(string[] args)
{
long count = 0;
while (true)
{
if (count++ % 100 == 0)
{
// sleep for a while to ensure we aren't using up the whole CPU
System.Threading.Thread.Sleep(50);
}
BuildCanvas();
}
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
private static void BuildCanvas()
{
Canvas c = new Canvas();
Line line = new Line();
line.X1 = 1;
line.Y1 = 1;
line.X2 = 100;
line.Y2 = 100;
line.Width = 100;
c.Children.Add(line);
c.Measure(new Size(300, 300));
c.Arrange(new Rect(0, 0, 300, 300));
}
}
}
NOTE: the first answer below is a bit off-base since I explicitly stated already that this same behavior occurs during a WPF application's button click event. I did not explicitly state, however, that in that app I only do a limited number of iterations (say 1000). Doing it that way would allow the GC to run as you click around the application. Also note that I explicitly said I've taken a memory dump and found my objects were rooted via !gcroot. I also disagree that the GC would not be able to run. The GC does not run on my console application's main thread, especially since I'm on a dual core machine which means the Concurrent Workstation GC is active. Message pump, however, yes.
To prove the point, here's a WPF application version that runs the test on a DispatcherTimer. It performs 1000 iterations during a 100ms timer interval. More than enough time to process any messages out of the pump and keep the CPU usage low.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
namespace SimpleReproSampleWpfApp
{
public partial class Window1 : Window
{
private System.Windows.Threading.DispatcherTimer _timer;
public Window1()
{
InitializeComponent();
_timer = new System.Windows.Threading.DispatcherTimer();
_timer.Interval = TimeSpan.FromMilliseconds(100);
_timer.Tick += new EventHandler(_timer_Tick);
_timer.Start();
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
void RunTest()
{
for (int i = 0; i < 1000; i++)
{
BuildCanvas();
}
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
private static void BuildCanvas()
{
Canvas c = new Canvas();
Line line = new Line();
line.X1 = 1;
line.Y1 = 1;
line.X2 = 100;
line.Y2 = 100;
line.Width = 100;
c.Children.Add(line);
c.Measure(new Size(300, 300));
c.Arrange(new Rect(0, 0, 300, 300));
}
void _timer_Tick(object sender, EventArgs e)
{
_timer.Stop();
RunTest();
_timer.Start();
}
}
}
NOTE2: I used the code from the first answer and my memory grew very slowly. Note that 1ms is much slower and less iterations than my example. You have to let it run for a couple minutes before you start to notice growth. After 5 minutes it's at 46MB from a starting point of 30MB.
NOTE3: Removing the call to .Arrange completely eliminates the growth. Unfortunately, that call is pretty vital to my use since in many cases I'm creating PNG files from the Canvas (via the RenderTargetBitmap class). Without the call to .Arrange it doesn't layout the canvas at all.
I was able to reproduce your problem using the code you provided. Memory keeps growing because the Canvas objects are never released; a memory profiler indicates that the Dispatcher's ContextLayoutManager is holding on to them all (so that it can invoke OnRenderSizeChanged when necessary).
It seems that a simple workaround is to add
c.UpdateLayout()
to the end of BuildCanvas.
That said, note that Canvas is a UIElement; it's supposed to be used in UI. It's not designed to be used as an arbitrary drawing surface. As other commenters have already noted, the creation of thousands of Canvas objects may indicate a design flaw. I realise that your production code may be more complicated, but if it's just drawing simple shapes on a canvas, GDI+-based code (i.e., the System.Drawing classes) may be more appropriate.
WPF in .NET 3 and 3.5 has an internal memory leak. It only triggers under certain situations. We could never figure out exactly what triggers it, but we had it in our app. Apparently it's fixed in .NET 4.
I think it's the same as the one mentioned in this blog post
At any rate, putting the following code in the App.xaml.cs constructor solved it for us
public partial class App : Application
{
public App()
{
new HwndSource(new HwndSourceParameters());
}
}
If nothing else solves it, try that and see
Normally in .NET GC gets triggered on object allocation upon crossing a certain threshold, it does not depend on message pumps (I can't imagine it's different with WPF).
I suspect that Canvas objects are somehow rooted deep inside or something. If you do c.Children.Clear() right before the BuildCanvas method finishes, the memory growth slows down dramatically.
Anyway, as a commenter noted here, such usage of framework elements is pretty unusual. Why do you need so many Canvases?
Edit 2: Obviously not the answer, but was part of the back-and-forth among answers and comments here, so I'm not deleting it.
The GC never gets a chance to collect those objects because your loop and its blocking calls never end, and therefore the message pump and events never get their turn. If you used a Timer of some sort so that messages and events actually have a chance to process, you probably wouldn't be able to eat up all your memory.
Edit: The following does not eat up my memory as long as the interval is greater than zero. Even if the interval is just 1 Tick, as long as it isn't 0. If it's 0, we're back to the infinite loop.
public partial class Window1 : Window {
Class1 c;
DispatcherTimer t;
int count = 0;
public Window1() {
InitializeComponent();
t = new DispatcherTimer();
t.Interval = TimeSpan.FromMilliseconds( 1 );
t.Tick += new EventHandler( t_Tick );
t.Start();
}
void t_Tick( object sender, EventArgs e ) {
count++;
BuildCanvas();
}
private static void BuildCanvas() {
Canvas c = new Canvas();
Line line = new Line();
line.X1 = 1;
line.Y1 = 1;
line.X2 = 100;
line.Y2 = 100;
line.Width = 100;
c.Children.Add( line );
c.Measure( new Size( 300, 300 ) );
c.Arrange( new Rect( 0, 0, 300, 300 ) );
}
}