How to efficiently use Threads and locks

I'm writing a short program that computes the mandelbrot set. I have implemented threads, but ts my first time using them and i'm a little confused.
Thread thread1 = new Thread(() => bitmapRenderer.UpdateBitmap(0,height/8));
Thread thread2 = new Thread(() => bitmapRenderer.UpdateBitmap(height/8,2*height/8));
Thread thread3 = new Thread(() => bitmapRenderer.UpdateBitmap(2*height/8,3*height/8));
Thread thread4 = new Thread(() => bitmapRenderer.UpdateBitmap(3*height/8,4*height/8));
Thread thread5 = new Thread(() => bitmapRenderer.UpdateBitmap(4*height/8,5*height/8));
Thread thread6 = new Thread(() => bitmapRenderer.UpdateBitmap(5*height/8,6*height/8));
Thread thread7 = new Thread(() => bitmapRenderer.UpdateBitmap(6*height/8,7*height/8));
Thread thread8 = new Thread(() => bitmapRenderer.UpdateBitmap(7*height/8,height));

thread1.Start();
thread2.Start();
thread3.Start();
thread4.Start();
thread5.Start();
thread6.Start();
thread7.Start();
thread8.Start();
thread1.Join();
.
.
thread8.Join();
Thread thread1 = new Thread(() => bitmapRenderer.UpdateBitmap(0,height/8));
Thread thread2 = new Thread(() => bitmapRenderer.UpdateBitmap(height/8,2*height/8));
Thread thread3 = new Thread(() => bitmapRenderer.UpdateBitmap(2*height/8,3*height/8));
Thread thread4 = new Thread(() => bitmapRenderer.UpdateBitmap(3*height/8,4*height/8));
Thread thread5 = new Thread(() => bitmapRenderer.UpdateBitmap(4*height/8,5*height/8));
Thread thread6 = new Thread(() => bitmapRenderer.UpdateBitmap(5*height/8,6*height/8));
Thread thread7 = new Thread(() => bitmapRenderer.UpdateBitmap(6*height/8,7*height/8));
Thread thread8 = new Thread(() => bitmapRenderer.UpdateBitmap(7*height/8,height));

thread1.Start();
thread2.Start();
thread3.Start();
thread4.Start();
thread5.Start();
thread6.Start();
thread7.Start();
thread8.Start();
thread1.Join();
.
.
thread8.Join();
There probably is a better way to create, start and join threads, but i wasn't able to find anything better. Its not clear to me how threads work overall. I have a 16 thread CPU and using 8 threads bumped the usage from 10% to 30%. How can i find out what a good number of threads to use is?
lock (bmp)
{
bmp.SetPixel(j,i,iterToColor(iterCount_temp));
}
lock (bmp)
{
bmp.SetPixel(j,i,iterToColor(iterCount_temp));
}
I had to lock the bitmap so that the threads wouldn't try to write at the same time. But i feel like this isn't the best practise as the threads will wait on one another fairly often. I wanted to save the X Y Color values in some structure and write all at once after joining, but was not yet able to come up with anything. Any ideas?
11 Replies
jbizzy
jbizzy9mo ago
i would probably recommend using the task/async await model if you want to do something like that, rather than trying to manage raw threads yourself
JakenVeina
JakenVeina9mo ago
the first thing you need to understand about ANY of this is that you can only parallelize work that is parallelizable what is the work that you're trying to parallelize here? the bitmap computations you're doing, these can be done completely independently?
umbranocturna
umbranocturna9mo ago
I can compute each pixels color independently. Just the writing was a problem.
umbranocturna
umbranocturna9mo ago
This speeds it up a little, i get 100% cpu usage for a short time, but the writing to the bitmap seems to be a massive bottleneck. Memory usage jumped aswell.
No description
jbizzy
jbizzy9mo ago
You might try PLINQ Makes parallel computation very fast and easy, and automatically handles thread joining Then you just take the output of that and shove it in teh bitmap
umbranocturna
umbranocturna9mo ago
oh maybe i should have closed it, i have already made some improvements over yesterday. stored results as a matrix of short instead of color -> memory usage down from 15gb to 700mb writing results in bulk instead of individual pixels -> runntime down from 90 seconds to 26 But i will have a look at PlinQ, maybe thts interesting too
jbizzy
jbizzy9mo ago
yeah. would keep you from needing to deal w/ all the manual thread manipulation the setup you initially showed looks trivial to linqize
umbranocturna
umbranocturna9mo ago
ended up doing this
No description
umbranocturna
umbranocturna9mo ago
(credit to Chat when
jbizzy
jbizzy9mo ago
var parallelism = 8;//roughly equivalent to your threadcount
var pixels = Enumerable.Range(0,parallelism).AsParallel().Select(i=>(i,CalculatePixels(i*height/Parallelism))).ToList();
BitMap.Update(pixels);
var parallelism = 8;//roughly equivalent to your threadcount
var pixels = Enumerable.Range(0,parallelism).AsParallel().Select(i=>(i,CalculatePixels(i*height/Parallelism))).ToList();
BitMap.Update(pixels);
something kinda like that. you'd need to decompose your calculation and render functions though
umbranocturna
umbranocturna9mo ago
ill consider it, probably going to rewrite it multiple times anyway.