Click here to Skip to main content
15,923,164 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Hi,
I'm writing a program(academic project) which reads a 5000000-element-text-file and sorts it by merge sort, quick sort and exchange sort, by threading, and showing the progresses graphically.
I've only written merge sort, but there is a problem in showing the progress when I use thread!
For showing the progress, I used a picture box to make a custom progress bar, but it doesn't work. By the way, it works without thread and doesn't have any problem!
I need to show the progress by using a picture box!
Now, how can I figure this out??

somebody help me, please!

Thanks in advance.

And the code:
C#
public int[] arr1;
private void button1_Click(object sender, EventArgs e)
{
    if (InitializingData())
    {
        label1.Visible = true;
        Thread t1 = new Thread(delegate() { MergeSort(arr1); });
        t1.Start();
    }
}

private bool InitializingData()
{
    if (!File.Exists(Application.StartupPath + @"\input.txt"))
    {
        MessageBox.Show("The input file was not found!");
        return false;
    }
    try
    {
        #region Reading input file as a string array, and reserving space for input data
        StreamReader objFileReader = new StreamReader(Application.StartupPath + @"\input.txt");
        string[] str = objFileReader.ReadLine().Split(',');
        objFileReader.Dispose();
        arr1 = new int[str.Length];
        arr2 = new int[str.Length];
        arr3 = new int[str.Length];
        MessageBox.Show("The usage space was reserved successfully!!!");
        #endregion

        #region Putting input elements from the string array to integer array
        int cnt = 0;
        foreach (string obj in str)
        {
            arr1[cnt] = int.Parse(obj);
            arr2[cnt] = int.Parse(obj);
            arr3[cnt++] = int.Parse(obj);
        }
        MessageBox.Show("The input data initialized successfully!!!");
        #endregion
    }
    catch
    {
        MessageBox.Show("Wrong input!!!");
        return false;
    }
    return true;
}

#region Merge Sort...
private void MergeSort(int[] l_arr)
{
    int h = l_arr.Length / 2;
    int m = l_arr.Length - h;
    int[] left = new int[h];
    int[] right = new int[m];
    if (l_arr.Length > 1)
    {
        for (int i = 0; i < h; i++)
            left[i] = l_arr[i];
        for (int i = h, j = 0; i < l_arr.Length; i++, j++)
            right[j] = l_arr[i];

        MergeSort(left);
        MergeSort(right);
        Merge(left, right, l_arr);
    }
}

private void Merge(int[] left, int[] right, int[] l_arr)
{
    int arrIndex, leftIndex, rightIndex;
    arrIndex = leftIndex = rightIndex = 0;
    while (leftIndex < left.Length && rightIndex < right.Length)
    {
        if (left[leftIndex] < right[rightIndex])
            l_arr[arrIndex++] = left[leftIndex++];
        else
            l_arr[arrIndex++] = right[rightIndex++];
    }
    while (leftIndex < left.Length)
        l_arr[arrIndex++] = left[leftIndex++];
    while (rightIndex < right.Length)
        l_arr[arrIndex++] = right[rightIndex++];
    ShowProgressBar(pictureBox1, arr1.Length);
}
#endregion

#region Show progress bar
int cnt = 1;
private void ShowProgressBar(object sender, int max)
{
    PictureBox objProgressBar = (PictureBox)sender;
    Bitmap objBM = new Bitmap(objProgressBar.Width, objProgressBar.Height);
    Graphics objGraphic = Graphics.FromImage(objBM);
    objGraphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
    objGraphic.FillRectangle(Brushes.Violet, new Rectangle(0, 0, ((cnt++) * objProgressBar.Width) / max, objProgressBar.Height));
    try { objProgressBar.Image = objBM; }
    catch { }
    Application.DoEvents();
}
#endregion

-------------------------

I've changed ShowProgressBar to this:
C#
int cnt = 1;
        private void ShowProgressBar(object sender, int max)
        {
            
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(delegate { ShowProgressBar(sender, max); }));
            }
            else
            {
                PictureBox objProgressBar = (PictureBox)sender;
                Bitmap objBM = new Bitmap(objProgressBar.Width, objProgressBar.Height);
                Graphics objGraphic = Graphics.FromImage(objBM);
                objGraphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                objGraphic.FillRectangle(Brushes.Violet, new Rectangle(0, 0, ((cnt++) * objProgressBar.Width) / max, objProgressBar.Height));
                objProgressBar.Image = objBM;
                this.Text = (((cnt) * 100) / max).ToString() + '%';
            }
        }

------------------------

The QuickSort method:
C#
#region Quick Sort
        int pivotpoint;
        void QuickSort(int low, int high, int[] l_arr)
        {
            pivotpoint=low;
            if (high > low)
            {
                partition(low, high, l_arr);
                QuickSort(low, pivotpoint - 1, l_arr);
                QuickSort(pivotpoint + 1, high, l_arr);
            }
        }
        void partition(int low, int high, int[] l_arr)
        {
            int i, j;//, pivotpoint;
            int tmp;
            int pivotitem = l_arr[low];
            j = low;
            for (i = low + 1; i <= high; i++)
            {
                if (l_arr[i] < pivotitem)
                {
                    j++;
                    tmp = l_arr[i];
                    l_arr[i] = l_arr[j];
                    l_arr[j] = tmp;
                }
            }
            pivotpoint = j;
            tmp = l_arr[low];
            l_arr[low] = l_arr[pivotpoint];
            l_arr[pivotpoint] = tmp;
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(delegate { partition(low, high, l_arr); }));
            }
            else
            {
                ShowProgressBar(pictureBox2, arr2.Length);
            }
        }
        #endregion
Posted
Updated 18-May-13 0:32am
v6

1 solution

You can't access Controls except from the thread they were created on - the UI thread. When you try, you get an error, as you have seen.

Either use P/Invoke to update your picture box, or switch from an explicit thread to a BackgroundWorker which has progress reporting built in.
Invoke:
C#
private void ShowProgress(int percent)
    {
    if (InvokeRequired)
        {
        Invoke(new MethodInvoker(delegate { ShowProgress(percent); }));
        }
    else
        {
        ...
        }
    }


If you look on MSDN under BackgroundWorker Class[^] it gives an example which includes progress reporting.

But for goodness sake start Disposing of your objects! Both Bitmaps and Graphics contexts are scarce resources, and if you just create them without correctly disposing them, you will get an "Out of Memory" error long before you run out of RAM!

And get rid of Application.DoEvents! You are using threading, you really, really, do not want that in there!
 
Share this answer
 
Comments
salehne 16-May-13 9:14am    
Thank you OriginalGriff!

What you said works in merge sort without any problems, but in quick sort doesn't work and I encounter to 'stack overflow' error in 2% progress with a 500000-element-file!!

The error is:
'An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll'

what should I do now? what do you suggest me to do?

As a general rule, what is the solution for such errors?

And I've changed 'ShowProgressBar' function and updated the post!
OriginalGriff 16-May-13 9:59am    
There are two possible reasons for that:
The first is that you may have made an error in coding your Quicksort routine (I know, I know, you don't make mistakes...:laugh:)
The other is that Quicksort is seriously recursive - much more so than merge sort - and it is possible that the invokes are adding too much to the stack usage.

Let's find out: comment out the whole body of the ShowProgressBar method, so it is just the open and close curly brackets left. (You can do this very easily by highlighting all the lines, and pressing CTRL+K followed by CTRL+C)

Run it again. Does it work this time (but not show any progress)?
salehne 18-May-13 1:07am    
Hi,
No, it doesn't. The same error occurs again!
By the way, I added my QuickSort method above, take a look please!
OriginalGriff 18-May-13 4:29am    
A quick look says that the problem is your quick sort method: not sure what without debugging it for you, but if I copy and paste it into my code and try it:
int[] data = new int[] { 5, 4, 3, 2, 1 };
QuickSort(0, 4, data);
And it gives the wrong result:
1, 3, 4, 2, 5
So there is a basic problem in there somewhere.
I would recommend that you try it with a small range of values until it works first, then worry about the stack problem, because I suspect that fixing the one may fix the other!
Time for you to break out your Debugger-Fu! :laugh:
salehne 18-May-13 6:40am    
I corrected the QuickSort method, but the same error occurs! (I updated the post for QuickSort!)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900