title: Avoid ProgressDialog freeze during Parallel.ForEach (C# Xamarin Android)
body: <p>Based on topics and examples found here at stackoverflow, I wrote an "IP address server searcher" that is trying to connect via http to <strong>all</strong> possible IP addresses from 192.168.x.1 - 192.168.x.254 to find the first 2 PCs serving on a specific port.  </p>
  
  <p>It works perfectly fine and the Dialog is showing and updating 1....254 as long as either:<br>
  - I leave the connection timeout on <strong>2000ms</strong> inside the parallel loop (<strong>36sec</strong>), or<br>
  - I reduce to <strong>200ms</strong>, but do it one-by-one <strong>without</strong> using Parallel (takes <strong>22sec</strong>! :D)  </p>
  
  <p>BUT if I speed up the process by setting: .ConnectTimeout = 200; AND leaving it parallel>> 
  - the Dialog is stopping at 0%<br>
  - after <strong>8 sec</strong>onds it's finding 2 IPs,<br>
  - <strong>finishing</strong> the job, and the Dialog disappears.<br>
    <em>(no process update :( )</em>  </p>
  
  <p>Here is the code for the button:</p>
  
  <pre><code>&lt;!-- language: lang-cs --&gt;
  btnSearchAddress.Click += delegate {
      // ... get IP address of the WifiManager
      _PzzCID._myIPstring = Formatter.FormatIpAddress(i);
  
      // SHOW % in a dialog bar
      ProgressDialog progress;            
      progress = new Android.App.ProgressDialog( this );
      progress.SetCancelable(false);  
      _dialogCancelled = false; // static bool ... defined below
      progress.SetButton(-3, "STOP", (sender, e) =&gt; { // cancelling the search
          _dialogCancelled = true;
      });
      progress.Max = _MaxIP; // =254
      progress.SetIcon(Android.Resource.Drawable.IcMenuSearch);
      progress.SetProgressStyle(ProgressDialogStyle.Horizontal);  
      progress.SetMessage("Tested / Found IP addresses...");  
      progress.Show();
  
      var task = Task.Run( async () =&gt; { 
          await Task.Yield(); // force to run the commands from now on Async
          _FIND( edtPort.Text, edtDevicename.Text ); 
          while ( ! _dialogCancelled ) { //
              await Task.Delay( TimeSpan.FromMilliseconds(100));
              RunOnUiThread(() =&gt; {
                  progress.Progress = _started.Value;
                  //progress.Notify(); // would cause "not locked by thread ..." error
              });             
          };
          await Task.WhenAll();
          if (progress.IsShowing)
              progress.Dismiss();
  
          for (int j = 0; j &lt; _addresses.Count; j++) {
              _PzzCID.AddLog2List(_addresses[j]);
              if (j==0) RunOnUiThread(() =&gt; edtBaseurl1.Text = _addresses[0]); 
              if (j==1) RunOnUiThread(() =&gt; edtBaseurl2.Text = _addresses[1]);
          }    
      });
  }; // btnSearchAddress.Click
  </code></pre>
  
  <p>And here is the async called search loop:</p>
  
  <pre><code>const int _MaxIP = 254;
  public static bool _dialogCancelled = false;
  
  public static MultiThreadValues.ThreadSafeInt _started  = new MultiThreadValues.ThreadSafeInt(); // how many servers responded 
  public static MultiThreadValues.ThreadSafeInt _found    = new MultiThreadValues.ThreadSafeInt(); // how many servers responded 
  public static MultiThreadValues.ThreadSafeList&lt;string&gt; _addresses = new MultiThreadValues.ThreadSafeList&lt;string&gt;(); // each IP with server, who responded
  
  
  public static async void _FIND( string port, string name ) { 
      await Task.Yield();
      _started.Value = 0;
      _found.Value   = 0;
      _addresses.Clear();
      string p = _PzzCID._myIPstring;
      if (p == "") return;
      const Char _dot = '.';
  
      StringBuilder str192 = new StringBuilder(64);
      Int16 dots = 0;
      for (int c = 0; c &lt; p.Length; c++) {
          if ( p[c] == _dot)  dots++;
          str192.Append(p[c]);
          if (dots == 3) break; // found 3. "." = 192.168.1.
      }
      string str192168 = str192.ToString();
  
      const Int16 _numberOfthreads = 8;
  
      IEnumerable&lt;int&gt; _all_1_to_254 = Enumerable.Range (1, _MaxIP);
      // Parallel.ForEach(GetRateLimitedResource,
      Parallel.ForEach(_all_1_to_254, new ParallelOptions() { MaxDegreeOfParallelism = _numberOfthreads }, 
      async (i, StopMe) =&gt; {
          await Task.Yield();
          _started.Add1();
          //int s = _started.Value;
          //if (s &lt; _numberOfthreads) Thread.Sleep(500 * s); // useless
  
          bool success = false;
          var host0 = str192168 + i;
              string url_txt = WebCall.CreateTestURL(host0, port, name) ;
              URL myUrl = new URL (url_txt);
              try {
                  using (HttpURLConnection urlc = (HttpURLConnection)myUrl.OpenConnection ()) {
                      urlc.RequestMethod = "GET";  //OR  urlc.setRequestMethod ("HEAD"); 
                      urlc.SetRequestProperty("Connection", "close");
                      urlc.ConnectTimeout = 200;
                      await urlc.ConnectAsync();
                      success = (urlc.ResponseCode == HttpStatus.Ok); 
                  }
              }
              catch (Exception ex) {
                  //_addresses.Add("**ERROR:"+url_txt+ " --- " + ex.Message);
              }
              myUrl.Dispose();
  
          if (success) {
              _found.Add1();
              _addresses.Add(host0);
              if (_found.Value == 2) {
                  StopMe.Stop(); // Found 2 hosts &gt;&gt; Exit from for-loop
              }
          }
  
          if (_dialogCancelled &amp;&amp;  ! StopMe.IsStopped)   StopMe.Stop(); // StopMe is a ForEach state 
      }); // lambra ForEach
  
      _dialogCancelled = true; // force finish &gt;&gt; to dismiss the ProcessDialog automatically
  } //void _FIND()
  </code></pre>
  
  <p>Q.: How do I force-update (refresh) the ProcessDialog while we have heavy CPU load ?<br>
   <em>(If there is anything else I can improve, please share with me! :)</em></p>