-1

I want to make two thread, because I want to divide first for loop into 2 parts. Instead of for (var row = 0; row < area.Height; row++) I want to make for (var row = 0; row < area.Height/2; row++) and for (var row = area.Height/2; row < area.Height; row++) for each loop i want threads. I don't know how to implement this thing. can you help me ?

using System;
using System.Diagnostics;
using System.Drawing;
using System.Threading;

namespace MandelbrotGenerator {
  public class SyncImageGenerator : IImageGenerator {
    public void GenerateImage(Area area) {
      var sw = Stopwatch.StartNew();
      var bitmap = SyncImageGenerator.GenerateSyncroniously(area);
      GenerationDone(area, bitmap, sw.Elapsed);
    }

    public static Bitmap GenerateSyncroniously(Area area) { 
      int maxIterations;
      double zBorder;
      double cReal, cImg, zReal, zImg, zNewReal, zNewImg;

      maxIterations = Settings.DefaultSettings.MaxIterations;
      zBorder = Settings.DefaultSettings.ZBorder * Settings.DefaultSettings.ZBorder;

      Bitmap bitmap = new Bitmap(area.Width, area.Height);

      for (var row = 0; row < area.Height; row++) {
        for (var col = 0; col < area.Width; col++) {
          var pixelWidth = (area.MaxReal - area.MinReal) / area.Width;
          cReal = area.MinReal + col * pixelWidth;
          var pixelHeight = (area.MaxImg - area.MinImg) / area.Height;
          cImg = area.MinImg + row * pixelHeight;
          zReal = 0.0;
          zImg = 0.0;
          var iter = 0;
          while (zReal*zReal+zImg*zImg<zBorder && iter<maxIterations) {
            zNewReal = zReal * zReal - zImg * zImg;
            zNewImg = zImg * zReal + zReal * zImg;
            zNewReal = zNewReal + cReal;
            zNewImg = zNewImg + cImg;
            zReal = zNewReal;
            zImg = zNewImg;
            iter++;
          }
          bitmap.SetPixel(col, row, ColorSchema.GetColor(iter));
        }
      }

      return bitmap;
    }
    public event EventHandler<EventArgs<Tuple<Area, Bitmap, TimeSpan>>> ImageGenerated;
    private void GenerationDone(Area area, Bitmap bitmap, TimeSpan time) {
      if (ImageGenerated != null) {
        ImageGenerated(this, new EventArgs<Tuple<Area, Bitmap, TimeSpan>>(Tuple.Create(area, bitmap, time)));
      }
    }
  }
}

Actually, I don't know how to use all these variables and how to share all of them with 2 threads.

Giga
  • 98
  • 1
  • 2
  • 11
  • 1
    First, see http://www.codeproject.com/Articles/406045/Why-the-use-of-GetPixel-and-SetPixel-is-so-ineffic , http://www.codeproject.com/Articles/617613/Fast-Pixel-Operations-in-NET-With-and-Without-unsa , and http://stackoverflow.com/questions/24701703/c-sharp-faster-alternatives-to-setpixel-and-getpixel-for-bitmaps-for-windows-f – user2864740 Dec 13 '15 at 00:35
  • thanks for these. can you suggest how can i easily divide this loop for threads ? – Giga Dec 13 '15 at 00:40
  • Just as you described, but actually *use* threads. There are many thread tutorials online. Create / start the threads supplying the appropriate domain information (or use `Parallel.ForEach`, noting that, unlike a manual Thread impl, it can decide how many threads to actually use) and then wait for the completion. In any case, there will likely be a much better performance improvement merely by avoiding SetPixel.. – user2864740 Dec 13 '15 at 00:44

1 Answers1

-1

Don't directly use threads when there are plenty of good abstractions to choose from. TPL is one, but I prefer Microsoft's Reactive Framework (NuGet "Rx-Main"). With it you can do this:

public static IObservable<Bitmap> GenerateAsynchronously(Area area)
{
    int maxIterations = 100;
    double zBorder = 1.0;

    var compute =
        from row in Observable.Range(0, area.Height)
        from col in Observable.Range(0, area.Width)
        from iter in Observable.Start(() =>
        {
            var pixelWidth = (area.MaxReal - area.MinReal) / area.Width;
            double cReal = area.MinReal + col * pixelWidth;
            var pixelHeight = (area.MaxImg - area.MinImg) / area.Height;
            double cImg = area.MinImg + row * pixelHeight;
            double zReal = 0.0;
            double zImg = 0.0;
            var i = 0;
            while (zReal * zReal + zImg * zImg < zBorder && i < maxIterations)
            {
                double zNewReal = zReal * zReal - zImg * zImg;
                double zNewImg = zImg * zReal + zReal * zImg;
                zNewReal = zNewReal + cReal;
                zNewImg = zNewImg + cImg;
                zReal = zNewReal;
                zImg = zNewImg;
                i++;
            }
            return i;
        })
        select new { row, col, iter };

    var query =
        from xs in compute.ToArray()
        from bm in Observable.Start(() =>
        {
            Bitmap bitmap = new Bitmap(area.Width, area.Height);
            foreach (var x in xs)
            {
                bitmap.SetPixel(x.col, x.row, ColorSchema.GetColor(x.iter));
            }
            return bitmap;
        })
        select bm;

    return query;
}

Now you are returning an IObservable<Bitmap> rather than Bitmap. You consume this like so:

    var bitmapObservable = SyncImageGenerator.GenerateAsynchronously(area);
    bitmapObservable
        .Subscribe(bitmap =>
        {
            GenerationDone(area, bitmap);
        });

No need to manage threads at all, but you get maximum concurrency.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • While Rx is nice for certain problems, I doubt (although willing to entertain numbers) that such is well-suited for the task at hand .. – user2864740 Dec 13 '15 at 01:33
  • Thanks a lot for that, but i just want some simple code with implemented threads or semaphores to divide for loop, to make some kind of parallelization. – Giga Dec 13 '15 at 01:53
  • @user2864740 - Why don't you think it is well suited for this particular task? – Enigmativity Dec 13 '15 at 01:58
  • @Giga - As soon as you try to "roll your own" threads and use semaphore you are likely to create very complicated code that is likely to be buggy. Writing correct threaded code is hard. You should almost always use a library that abstracts it all for you. – Enigmativity Dec 13 '15 at 01:59
  • @Enigmativity Because of the overhead involved. Increasing parallelism is not always the solution. If not wanting to 'manage threads', my primary recommendation is a simple conversion to `Parallel.ForEach`, with range split as the OP envisioned. Again, *actual numbers* for such an approach would be interesting.. – user2864740 Dec 13 '15 at 21:13
  • @user2864740 - Using Rx doesn't increase parallelism any more than using `Parallel.ForEach`, except that it can run different tasks in parallel. – Enigmativity Dec 13 '15 at 22:03
  • @user2864740 - And when you say *actual numbers*, what do you mean? Number of threads, time taken, etc? – Enigmativity Dec 13 '15 at 22:04
  • @Enigmativity Preferably wall-clock time, given a particular environment (pref. 2 + 4 core situations). The Parallel.ForEach approach, following the primary question idea of a split-in-two, would only create two tasks (= 2 threads, max). Excluding the use of another thread, if any, it also imposes very little overhead compared to the original code – user2864740 Dec 13 '15 at 22:49
  • 1
    @user2864740 - Well, it's interesting. A plain enumerable approach takes 80ms (in one particular test I created) using one thread (obviously). An `.AsParallel()` version of the same test takes 50ms and uses 4 threads. But the `Observable` version takes 140ms using 8 threads (usually). The difference comes when the computation becomes more expensive as the 8 threads overtakes in the performance race. The other consideration is that the `Observable` approach comes with all of the other operators for advanced computation that you just don't get with `.AsParallel()`. – Enigmativity Dec 14 '15 at 01:30