private unsafe void OnRunButtonClick(object sender, EventArgs e) { if (!EstimateTime(false)) { return; } double start, end; double.TryParse(startTextBox.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out start); double.TryParse(endTextBox.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out end); if (estimatedTime.TotalMinutes > 0.5) { string timeString; if (estimatedTime == TimeSpan.MaxValue) { timeString = Tx.T("time.infinitely"); } else { timeString = estimatedTime.ToTextString(); } if (MessageBox.Show(this, Tx.T("find diffs.errors.interval too big", Tx.N(distance), timeString), Tx.T("main.warning"), MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK) { return; } } long starti = *(long *)&start; long endi = *(long *)&end; if (starti > endi) { long swap = starti; starti = endi; endi = swap; } distance = (endi - starti); long currentProcessed = 0, lastProcessed = 0; long differencesFound = 0; SpinLock syncLock = new SpinLock(); ProgressDialog progressDialog = new ProgressDialog { Text = Tx.T("find diffs.finding.title"), MainInstruction = Tx.T("find diffs.finding.description"), Line1 = Tx.T("find diffs.finding.progress", "0", Tx.N(distance)), ShowInTaskbar = false, MinimizeBox = false }; ThreadPool.UnsafeQueueUserWorkItem(delegate { BeginInvoke((MethodInvoker) delegate { progressDialog.ShowDialog(this); }); Stopwatch sw = Stopwatch.StartNew(); Parallel.For(starti, endi, (xi, state) => { double x = *(double *)ξ bool isFirst = true; double computedMinY = double.MaxValue, computedMaxY = double.MinValue; foreach (ListView.Item item in listView.Items) { if (item.NumericValueSource == null || item.CheckState != CheckState.Checked) { continue; } double y = item.NumericValueSource.Evaluate(x); if (isFirst) { isFirst = false; computedMinY = y; computedMaxY = y; } else { if (y > computedMaxY) { computedMaxY = y; } else if (y < computedMinY) { computedMinY = y; } } } bool lockTaken = false; syncLock.Enter(ref lockTaken); if (!isFirst && computedMinY != computedMaxY) { graph.AddDifferenceUnsafe(x, computedMinY, computedMaxY); differencesFound++; } if (sw.ElapsedMilliseconds > 4000) { if (progressDialog.IsCancelled) { if (lockTaken) { syncLock.Exit(); } state.Stop(); return; } sw.Stop(); long delta = (currentProcessed - lastProcessed); long rate = delta * 1000 / (long)sw.Elapsed.TotalMilliseconds; TimeSpan remaining = TimeSpan.FromSeconds((distance - currentProcessed) / rate); lastProcessed = currentProcessed; BeginInvoke((MethodInvoker) delegate { progressDialog.Line1 = Tx.T("find diffs.finding.progress", Tx.N(lastProcessed), Tx.N(distance)); progressDialog.Line2 = Tx.T("main.remaining time", remaining.ToTextString()); progressDialog.Progress = (int)(lastProcessed * 100 / distance); }); sw.Restart(); } currentProcessed++; if (lockTaken) { syncLock.Exit(); } }); sw.Stop(); BeginInvoke((MethodInvoker) delegate { progressDialog.TaskCompleted(); if (!progressDialog.IsCancelled) { MessageBox.Show(this, Tx.T("find diffs.complete.description", Tx.N(distance), Tx.N(differencesFound), Tx.N(differencesFound * 100 / distance)), Tx.T("find diffs.complete.title"), MessageBoxButtons.OK, MessageBoxIcon.Information); } }); }, null); }