I think I've nailed it - partially.
I have found out that the -at least in editing mode- plugin calls the Render() method a lot of times, even when one has done some single eidting change and wait for the code to redraw. It seems to start a thread for each line or some a group of lines. See this code (warning: it write on your C:\temp\ dir, adjust it if you need it)
#region UICode
#endregion
bool inLoop;
void Render(Surface dst, Surface src, Rectangle rect)
{
inLoop=false;
ColorBgra CurrentPixel;
byte v=0;
try {
System.IO.StreamWriter sr = new System.IO.StreamWriter(@"C:/temp/codelabtest.txt",true);
sr.Write("inLoop="+inLoop + " Top=" + rect.Top + "\n");
sr.Close();
} catch(Exception e) {}
inLoop=true;
for (int y = rect.Top; y < rect.Bottom; y++)
{
for (int x = rect.Left; x < rect.Right; x++)
{
CurrentPixel = src[x,y];
CurrentPixel.R = v;
CurrentPixel.G = v;
CurrentPixel.B = v;
dst[x,y] = CurrentPixel;
}
}
inLoop=false;
}
The writing to the file sometimes fails (with "file used by another process" error), but sometimes it works, and prints a lot of lines (try with a small image), and sometimes it prints "inLoop=true" (big warning!)
The moral is that a Render() function should be stricyl thread-safe.
My former code, actually, does not have a concurrency problem, as a new Random object is obtained locally in each Render() call. BUT the problem is (I guess) that the several Random() objects that are obtained are internally seeded with some system timestamp that happens to be the same. Because of this, consecutive lines will have -probably- the same random sequence.
An alternative would be to seed the Random object with some combination of timestamp plus rect coordinates.
But a more elegant/secure approach seems to have a single Random objects, as a class attribute.
However, it seems that the Random class does not like to be called simulateously from several threads (no idea why).
I must synchronize the access, to make it work:
#region UICode
#endregion
Random rand = new Random();
void Render(Surface dst, Surface src, Rectangle rect)
{
ColorBgra CurrentPixel;
byte v=0;
for (int y = rect.Top; y < rect.Bottom; y++)
{
for (int x = rect.Left; x < rect.Right; x++)
{
CurrentPixel = src[x,y];
v = getRandByte();
CurrentPixel.R = v;
CurrentPixel.G = v;
CurrentPixel.B = v;
dst[x,y] = CurrentPixel;
}
}
//inLoop=false;
}
[system.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
public byte getRandByte() {
return (byte)rand.Next(256);
}
You can experiment the difference by commenting out the Synchronized annotation.