So I have been working on a program lately, or actually was working on it and came back to check on it. The program is being developed for someone else, who unfortunately has not been cooperative in giving me the stuff I need to test it. The program is used to read in a webpage, parse its data, and then notify if changes have occurred.

Now this program involves using Threads, something that while I understand the concept of, and have gone over, I have never really implemented into a program like this (I have used BackgroundWorkers before but this is not the same).

Well from what I can tell the program actually works as intended. While I am unable to get the site needed to test it, I have been giving it other sites to give me general results. The program I know reads in results and does indeed try to update the form (it yelled at me saying it couldn't add rows until it had columns ... hazaa I got this far).

I decided to test the code today, as I mentioned before I hadn't worked on it in awhile, and everything seems fine (again like I said before). I also ran task manager and monitored the resources of the program, and here lies the problem ... I think I have a memory leak. Let me show you the code and I'll explain more after that.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace ScoreTableDetector2_1v1
{
    public delegate void Return_CallBack(string downloadedData);
    public delegate void Return_FormData(List<teamDataItem> tempData, string rtbData);
    public delegate void SetRTBCallback(string text);
    public delegate void SetDGV_New_Callback(teamDataItem tempEntry);
    public delegate void SetDGV_Edit_Callback(teamDataItem tempEntry);
//===================================================================================================================
    public partial class Form1 : Form
    {
        //!!!! - NEED to dispose of the thread and its resources when it's finished, primarily speaking of the delegate called threads for the form and parsing data.

        private Object thisLock = new Object();
        private Object lockFormUpdate = new Object();

        private Thread updateForm_Thread = null;
        private Thread updateForm_Thread_num2 = null;

        List<teamDataItem> teamData;

        List<string> pointFields;
        List<string> flagNames;

        Thread readInThread = null;
        string url;
        int elapsedTime;

        readInWebpage readIn;
//-------------------------------------------------------------------------------------------------------------------
        public Form1 ()
        {
            InitializeComponent();

            teamData = new List<teamDataItem>();

            pointFields = new List<string>() { };
            flagNames = new List<string>() { };

            url = "http://www.reddit.com/new/";
            elapsedTime = 15;

            readIn = new readInWebpage(url, "", elapsedTime, new Return_CallBack(updateForm));

            button2.Enabled = false;

            setupDataGridView.setup(ref pointFields, ref flagNames, ref dataGridView1); //used to set up the columns
        }
//-------------------------------------------------------------------------------------------------------------------
        private void button1_Click (object sender, EventArgs e) //start
        {
            checkWebsite();
        }
//-------------------------------------------------------------------------------------------------------------------
        private void button2_Click (object sender, EventArgs e) //stop
        {
            readInThread.Abort();

            button2.Enabled = false; //change over the state of the buttons to prevent double click issues
            button1.Enabled = true;
        }
//-------------------------------------------------------------------------------------------------------------------
        private void checkWebsite () //used to start the thread
        {
            this.readInThread = new Thread(readIn.runScan);
            readInThread.Start();

            button2.Enabled = true; //change over the state of the buttons to prevent double click issues
            button1.Enabled = false;
        }
//-------------------------------------------------------------------------------------------------------------------
        private void updateForm (string downloadedData) //the delegate class to call back to 
        {
            lock (thisLock) //lock (mutex style)
            {
                this.updateForm_Thread = new Thread(() => parseData.strip(teamData, downloadedData, pointFields, flagNames, new Return_FormData(updateForm_Data))); //parse the data
                this.updateForm_Thread.Start();

                //!!! when the updateForm_Data() function is called, this needs to be disposed of
            }
        }
//-------------------------------------------------------------------------------------------------------------------
        private void updateForm_Data (List<teamDataItem> tempData, string rtbData) //call back by the parseData
        {
            lock (lockFormUpdate) //lock off the form update to one class
            {
                this.updateForm_Thread_num2 = new Thread(() => thread_UpdateFormSafe(tempData, rtbData)); //used to actually apply the updated data to the form
                this.updateForm_Thread_num2.Start();

                //!!! once the form has been updated this needs to be disposed of
            }
        }
//-------------------------------------------------------------------------------------------------------------------
        private void thread_UpdateFormSafe (List<teamDataItem> tempData, string rtbData) //used to update the form data
        {
            //!!!!! I NEVER UPDATE THE COMBOBOX (needs to be done through new entry only)

            //if index == -1, and newEntry == true, then it's a new entry
            //if index != -1, and newEntry == false, then it's an old entry who's value changed
            //if index == -1, and newEntry == false, then it's an old entry that was unchanged


            for (int i = 0; i < tempData.Count; i++) //go through the list 
            {
                if (tempData [i].newEntry == true) //if a new entry was added
                {
                    this.addToDataGridView(tempData [i]);
                }
                else
                {
                    if (tempData [i].index != -1) //an existing entry was updates
                    {
                        this.editDataGridView(tempData [i]);
                    }
                }
            }

            //!!!! ADD - the richTextBox display
        }
//-------------------------------------------------------------------------------------------------------------------
        private void addToDataGridView (teamDataItem tempEntry) //updates dataGridView1 by adding a new item (in thread safe)
        {
            if (this.dataGridView1.InvokeRequired) //if the calling thread is different then the one that created dataGridView1
            {
                SetDGV_New_Callback dgvCall = new SetDGV_New_Callback(addToDataGridView);
                this.Invoke(dgvCall, new object [] { tempEntry });
            }
            else //if the same thread that created dataGridView1
            {
                dataGridView1.Rows.Add();
                dataGridView1.Rows [dataGridView1.RowCount - 1].HeaderCell.Value = tempEntry.teamName;

                for (int i = 0; i < pointFields.Count; i++) //adds the point fields
                {
                    dataGridView1 [i, (dataGridView1.Rows.Count - 1)].Value = tempEntry.points [i];
                }
                for (int i = 0; i < flagNames.Count; i++) //adds the flag fields
                {
                    dataGridView1 [(pointFields.Count + i), (dataGridView1.Rows.Count - 1)].Value = tempEntry.flags [i]; //remember it must pass by the pointFields first
                }
            }
        }
//-------------------------------------------------------------------------------------------------------------------
        private void editDataGridView (teamDataItem tempEntry) //updates dataGridView1 by editing an existing line (in thread safe)
        {
            if (this.dataGridView1.InvokeRequired) //if the calling thread is different then the one that created dataGridView1
            {
                SetDGV_Edit_Callback dgvCall = new SetDGV_Edit_Callback(editDataGridView);
                this.Invoke(dgvCall, new object [] { tempEntry });
            }
            else //if the same thread that created dataGridView1
            {
                int indexFound = -1;
                for (int i = 0; i < dataGridView1.RowCount; i++) //looks for the index
                {
                    if (tempEntry.teamName == dataGridView1.Rows [i].HeaderCell.Value.ToString()) //found the same team
                    {
                        indexFound = i;
                        break;
                    }
                }

                if (indexFound != -1) //we found an entry
                {
                    for (int i = 0; i < pointFields.Count; i++) //adds the point fields
                    {
                        dataGridView1 [i, indexFound].Value = tempEntry.points [i];
                    }
                    for (int i = 0; i < flagNames.Count; i++) //adds the flag fields
                    {
                        dataGridView1 [(pointFields.Count + i), indexFound].Value = tempEntry.flags [i]; //remember it must pass by the pointFields first
                    }
                }

                //!!! No else in case a fluke happens and we need to add a new row instead (implement later)
            }
        }
//-------------------------------------------------------------------------------------------------------------------
    }
//===================================================================================================================
}

Now you'll see I have left commented code in there relating to my problem, at least where I think it lies. I have these threads that are used to parse the data, as well as add the data to the form. The initial thread that is calls in the checkWebsite() function, only calls that thread once, then there's a infinite while loop that has a timer (okay actually it's a subtract two DateTime values and if the time span is larger then x) that when executed reads in the webpage (using a cURl plugin).

I am going to assume that readInThread.Abort(); line is okay for stopping that thread.

Anyway that's side tracked from the real problem, which is I have threads starting for the updateForm() and updateForm_Data() functions, but I never end them. Now when I watched the resource manager the CPU usage never went above 13% (please don't patronize me on that, I am new at this okay), but the memory usage I would watch go up and down, but was always progressively getting higher and higher.

I feel the automated garbage collector is the problem here and those classes in the functions I listed above are not being disposed off.

My question then is (and sorry it took me so long to get to this) how can I detect when these threads are done with their job and dispose them of their resources? They will be called again, as you can see it's reoccuring, but based on my knowledge of threads, I am create new threads everytime, which means all new resources.

I appreciate any help I can get, once again this is the first time I have worked with threads on this level, which I know can be a risky move. If you care to see some of my other classes, I can provide those (for instance the class that reads in the webpage using cURl). Or if maybe you see something else that's causing the problem I am listening. If I get this program to function properly, it could be a base model for when I build programs that use Threading in the future (there's already one I am waiting to build once I know this works).

Once again Thanks for any help

Recommended Answers

All 10 Replies

how can I detect when these threads are done with their job and dispose them of their resources?

I think the ThreadState property will tell you want you need to know.

The threads should manage and maintain their own resources. Also, please don't call Thread.Abort to end threads as this could cause bad things to happen (Memory Management issues and such) :P

You can signal thread closure easily by shared memory, a simple Boolean CloseThread; and check for this. Personally, I'd mutex the threads and make them wait if they don't need to do anything (This will also reduce the resources used if they don't have to run often)
Additionally, I'd be threading separate classes, not methods on your form. It's not a requirement, just the way I design things, but it stops your form code getting "too busy".

If the threads are being mutex'd you can cancel the mutex; this throws a very specific exception, you should catch it around the point you wait for the mutex and then cleanup the thread.

If you're using delegate invocation (which I think you only use for the form update) then unless you have a loop inside the called method, the method is only run once.

With regards to creating your threads over and over again; this is bad for performance in my opinion, when you can use flow control inside the thread itself.

I would:
Create Thread
Run Thread
Thread 1 does its thing
Main thread does other stuff
Thread 1 finishes its task and waits.
Main thread decides it needs to run Thread 1 again
Main thread allows Thread 1 to perform another iteration
Thread 1 starts its task
Main thread decides its time to quit
Main thread signals active threads to finish
Main thread waits for all threads to finish
Thread 1 finishes its task
All threads are finished (in the wait state)
Main thread cancels all mutexes
Thread 1 performs cleanup
Thread 1 is disposed
Application exits

I would, wherever possible, avoid aborting threads unless absolutely necessary (application crash etc)

It's quite complicated to do it the right way, but performance and resources will benefit.

I think the ThreadState property will tell you want you need to know.

So first of all I looked into ThreadState, and to be honest I wasn't quite sure about using it. I just remember that trying to reference a thread can be very dangerous, if even possible (excuse me if I sound like a total idiot here). Well MSDN help reassure me of this, saying that ThreadState should really only be used for debugging purposes

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

@Ketsuekiame

You first suggest I don't use Abort, can you give a proper example of how I should stop a thread? The class has an infinite while loop, so assuming you stop it at the right time you won't hurt much, but if you are trying to load in a webpage, well then that's another story. The problem here is that the process of reading in a webpage can take easily 5 - 10 secs, meaning waiting there could be a time consumer.

Also you mention shared memory, how exactly would I go about doing this in C#? I know there's unsafe, but just the concept of shared memory has me shuttering something's going to go haywire (maybe there's something I don't know about).

Also for the threads, I got thinking about it and did some edits to my code ... well a start. I was hoping you could clear me up if I was on the right path (note the last 3 functions for the form have remained unchanged, and as such were not added).

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace ScoreTableDetector2_1v1
{
    public delegate void Return_CallBack(string downloadedData);
    public delegate void Return_FormData(List<teamDataItem> tempData, string rtbData);
    public delegate void SetRTBCallback(string text);
    public delegate void SetDGV_New_Callback(teamDataItem tempEntry);
    public delegate void SetDGV_Edit_Callback(teamDataItem tempEntry);
//===================================================================================================================
    public partial class Form1 : Form
    {
        //!!!! - NEED to dispose of the thread and its resources when it's finished, primarily speaking of the delegate called threads for the form and parsing data.


        private Object thisLock = new Object();
        private Object lockFormUpdate = new Object();

        private Thread updateForm_Thread = null;
        private Thread updateForm_Thread_num2 = null;

        List<teamDataItem> teamData;

        List<string> pointFields;
        List<string> flagNames;

        Thread readInThread = null;
        string url;
        int elapsedTime;

        readInWebpage readIn;

        string downloadedData;
        List<teamDataItem> tempData;
        string rtbData;

//-------------------------------------------------------------------------------------------------------------------
        public Form1 ()
        {
            InitializeComponent();

            teamData = new List<teamDataItem>();

            pointFields = new List<string>() { };
            flagNames = new List<string>() { };

            url = "http://www.reddit.com/new/";
            elapsedTime = 15;

            readIn = new readInWebpage(url, "", elapsedTime, new Return_CallBack(updateForm));

            button2.Enabled = false;

            setupDataGridView.setup(ref pointFields, ref flagNames, ref dataGridView1); //used to set up the columns

            downloadedData = "";
            tempData = new List<teamDataItem>();
            rtbData = "";

            this.updateForm_Thread = new Thread(() => parseData.strip(teamData, downloadedData, pointFields, flagNames, new Return_FormData(updateForm_Data)));
            this.updateForm_Thread_num2 = new Thread(() => thread_UpdateFormSafe(tempData, rtbData)); 
        }
//-------------------------------------------------------------------------------------------------------------------
        private void button1_Click (object sender, EventArgs e) //start
        {
            checkWebsite();
        }
//-------------------------------------------------------------------------------------------------------------------
        private void button2_Click (object sender, EventArgs e) //stop
        {
            readInThread.Abort();

            button2.Enabled = false; //change over the state of the buttons to prevent double click issues
            button1.Enabled = true;
        }
//-------------------------------------------------------------------------------------------------------------------
        private void checkWebsite () //used to start the thread
        {
            this.readInThread = new Thread(readIn.runScan);
            readInThread.Start();

            button2.Enabled = true; //change over the state of the buttons to prevent double click issues
            button1.Enabled = false;
        }
//-------------------------------------------------------------------------------------------------------------------
        private void updateForm (string downloadedData) //the delegate class to call back to 
        {
            lock (thisLock) //lock (mutex style)
            {
                //this.updateForm_Thread = new Thread(() => parseData.strip(teamData, downloadedData, pointFields, flagNames, new Return_FormData(updateForm_Data))); //parse the data

                this.downloadedData = downloadedData;

                this.updateForm_Thread.Start();

                //!!! when the updateForm_Data() function is called, this needs to be disposed of
            }
        }
//-------------------------------------------------------------------------------------------------------------------
        private void updateForm_Data (List<teamDataItem> tempData, string rtbData) //call back by the parseData
        {
            lock (lockFormUpdate) //lock off the form update to one class
            {
                //this.updateForm_Thread_num2 = new Thread(() => thread_UpdateFormSafe(tempData, rtbData)); //used to actually apply the updated data to the form

                this.tempData = tempData;
                this.rtbData = rtbData;

                this.updateForm_Thread_num2.Start();

                //!!! once the form has been updated this needs to be disposed of
            }
        }

So here I have moved the initial declarations for the threads, this way I am not constantly making new ones. Now of course this will break. I tried it, and it yelled at me the Start() statement. I have a feeling this issue leads back to my inital question of detecting when it's done (by the way I don't know if this matters or not, but the function call strip in the parseData class is static).

You mentioend using Mutexes (which I do know what those are, well more primarily the concept of them from my OS class, but I have never used them in C#, are rarely in Linux), is this a possible way to get around my problem? If so, could I get an example? If I recall right, aren't they assigned to the thread?

Thanks for the help so far

It's all not as scary as it used to be in C++.

My 'ye olde' terminology may have been a contributing factor.

By shared memory I simply mean a variable that can at least be read by two or more threads.

So for example a Boolean closeThread; would be sufficient.

As for not using Thread.Abort, I'm of the opinion that you should let a thread finish its current task before closing it. Threads (again in my opinion) should be used to perform small atomic tasks. I know that sometimes this cannot be the case though.

Effectively you can have a single execution thread or a loop thread. In either case, there is a defined "beginning and end" to the thread's task. Rather than aborting a Thread partway through its task, allow it to complete the full task.

Ever notice how a program that performs a background task won't shut down until the task has finished? :)

When you create a thread you do not continually call Start. This is just to start processing. A thread will usually loop internally. If you have only a single execution, like you do, it may be worth looking at delegates as they can be invoked on demand. There is, however, overhead.

So to use a mutex, you were partially right, however there is an important rule. A mutex should never be altered by any thread other than the one it was created on. This is commonly your controlling thread, in our case, Main.

You will need to create an AutoResetEvent this type of mutex closes automatically as a thread passes "through" it.
Secondly, you will need to create a CancellationToken (from a CancellationTokenSource)

This token, you pass to your resetevent.Wait.

AutoResetEvent myMutex = new AutoResetEvent();
CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;

void ThreadingMethod()
{
    while(true)
    {
        try
        {
            myMutex.WaitOne(token);
        }
        catch(OperationCanceledException)
        {
            /* Do cleanup */
            return;
        }

        /* Do processing */
    }
}

There's not much more to it than that. If I get time at lunch today I will try and knock up a quick example.

PS. I know that thread cancellation looks very similar to aborting a thread, but with aborting the thread, there is no guarantee that:
A) The thread will receive the message
B) The thread will actually abort
C) You will be able to dispose objects used by the thread

Finally, some people disagree with the way that I handle threading. Many people I speak to believe that Mutexes should only be used where Thread concurrency is required, not as a signalling mechanism.

Your other option is to use event driven delegates on the thread pool. This might actually serve your purpose better, but threading is awesome to learn :)

Okay so I read over this, and I think I am getting most of it. I'll hold off on the Mutexes for now, just because I want to make sure I understand everything clearly.

First of all I forgot to mention this but the readIn class that's responsible for reading in websites, the while loop is using a bool value that is constantly checking if it's false, meaning if I set it to true, the loop stop (and we are not periodically checking the page).

public void runScan () //scans the webpage (periodically)
{
    stopRun = false;

    DateTime now = DateTime.UtcNow;

    while (stopRun == false)
    {
        if ((DateTime.UtcNow - now).Seconds > elapsedTime) //every x secs check (elapsedTime passed in)
        {
            this.readIn();
            now = DateTime.UtcNow; //update the time
        }
    }
}

See this is the function that the one thread is assigned to in main like this.

this.readInThread = new Thread(readIn.runScan);

I also didn't realize that since I declared the class ahead of time as readIn, that I can actually pass in values to it. See the thing that keeps messing with me is that I thought once you created a thread, it's kind of hard to reference it. You can't just access that one thread with it's declared variable name, because there could be multiple threads all that were started with the same name ... am I right? That's why you use delegates for returning values. All the classes that are called use a delegate to return values as you saw in main.

But even when doing this, I still am not sure how to start and restart a thread. I know Start() is used to get the process going, but what's bugging me is the execution of a function. Yes I could set a boolean to false that pretty much tells the class that while your running on this thread don't do anything till this boolean becomes true, but then wouldn't I need to call the function once I toggle the variable?

I want to assume this is where delegates comes into play. I have never been able to fully grasp the concept of delegates before but I think I finally have. Isn't a delegate kind of like the equivalance of a pointer? So when you mention Invoke a delegate, do you mean I use a delegate to call a function within a class within a specified thread? Like the delegate allows me to kind of keep track of that thread's class? (remember how I said you can't follow a thread by just it's declared name).

I really hope I am on the right track. I really want to learn how to properly implement threads. I guess what I am asking is just how exactly is a proper way to start and restart a thread (the readInThread for instance starts with the the button1 click and stops with the button2 click, and the other threads are static classes that just need to do work one time each time called).

Also I did some tweaks to the Form1() code, but to save space I pasted it on pastebin. Here's the link
http://pastebin.com/SGkB2Rju

Thanks for all the help, again I really want to understand this, and am trying my best to wrap my mind around it.

UPDATE: Whoops I forgot about the Thread Pooling, I have started to look into that, and maybe that is what I want, I don't know, I'll have to follow up on that

I think event driven code and delegates is actually more appropriate for you here. Actual threading programming is more about when you want to do concurrent processing (more than one job at once) where delegates and events are more "I want to perform <that> task when <this> happens"

So, a better solution may be to utilise a timer, set it to go off every second(?) and check if x seconds have passed. If so, call your thread for a single execution, no looping.

You're mostly correct where delegates are concerned. They are effectively pointers to methods, but they are not invoked on another thread by default. For that you would need to use BeginInvoke and EndInvoke pair of calls.
I do believe this is the most correct way of doing things for your application.

By utilising a loop and checking a boolean, you're effectively putting your thread in "SpinWait", meaning 'keep checking this condition until true and then execute code' which is very CPU intensive. Think how quickly your processor can iterate that loop ;)

Reading through your new code, I actually think you have too many threads involved.

It's good that you have a thread to read the information from the site. However, your callback, which I believe is just a delegate, will be called from the same thread as the one you started your readIn thread from and not the UI thread.
Then in your updateFormData method, you're starting a new thread that updates the backend data behind the DGV (if I'm reading this right). In my opinion, this is a superfluous call/thread. Esepcially as you have to invoke back to the UI thread to update the DGV anyway. So I believe you can get rid of those calls...

In pseudo:

Create ReadIn Thread Object
Event Fire: Time to update
Start ReadIn Thread
ReadIn Completes
ReadIn Calls DataUpdate Callback
Callback updates the form variables with current data (lock here on that single line)
Callback signals DGV update (mechanism may vary)
DGV invokes UI thread and updates

As you can see, only one thread object is required. It will execute once and complete. I think this will drastically simplify your program :)

First of all I do understand by what you mean BusyWaiting. I took an OS class last semester and we spent some time on Threading (how I have some knowledge of the concepts of it). Also yes once you mentioned it, this is more event driven where it's

  1. Read in a webpage
  2. Parse it's data and check for changes
  3. Populate the form items
  4. Repeat until stopped

Also and if you look at the code below (a little farther down), you'll see it is built on a timer current, I'll keep it working a BusyWaiting concept instead of Sleep/Wakeup for now (hmm, would a Sleep/Wakeup concept work?) until I know this version works as expected. I assume this is what you meant at least?

So let me make sure I understand you correctly. You mean to tell me when I call back to the main form with the delegate after reading in the data, that then goes on to call the parse data (does its thing in another class) and then I call back again with another delegate to update my information on the form, it' all in the same thread?

I am actually making a thread within a thread within a thread? (not literally but the idea). So what you're getting at is that I am still in the same thread despite the fact that I am using delegates (I though the delegates were jumping me out of the thread)? I mean now that you mention it, and from what we have said about Delegates, it kind of makes sense. I'll have to test this later tonight and get back to you. I really hope this is true, that would decrease my resource use for one.

So my next question. As you can see I have a button1 click and button2 click. Button1 is meant to start the read in event, while button2 is meant to stop it. But I want to allow the user to be able to start back up the readIn process. How do you suggest I go at it? I keep thinking to use join, because I tried just changing that boolean variable, but I realized the problem with that is the loop is killed then. This is what my loop looks like in the readIn (ignore that stopRun = false; that will probably have to removed in the future).

public void runScan () //scans the webpage (periodically)
{
    stopRun = false;

    DateTime now = DateTime.UtcNow;

    while (stopRun == false)
    {
        if ((DateTime.UtcNow - now).Seconds > elapsedTime) //every x secs check (elapsedTime passed in)
        {
            this.readIn();
            now = DateTime.UtcNow; //update the time
        }
    }
}

And remember when I click Button1 it calls this function (This is the old way I was doing it, and I am pretty sure I shouldn't be)

private void checkWebsite () //used to start the thread
{
    this.readInThread = new Thread(readIn.runScan);
    readInThread.Start();

    button2.Enabled = true; //change over the state of the buttons to prevent double click issues
    button1.Enabled = false;
}

And when I click button2 it does this (This is the old way I was doing it, and I am pretty sure I shouldn't be)

private void button2_Click (object sender, EventArgs e) //stop
{
    readInThread.Abort();

    button2.Enabled = false; //change over the state of the buttons to prevent double click issues
    button1.Enabled = true;
}

Once again thank you so much for the help. I hope I am not frustrating you, I probably sound really noobish right now, it's a lot to take in.

Oh and one other question (sorry I am making this more and more for you), you mentioned the Invoking and BeginInvoke of the Delegates. Care to enlighten me (or a good place to read up on it)? I was seeing this yesturday, but wasn't making whole sense of it (it's on the tip of my toungue).

UPDATE: I just realized the 2 button click pieces of code were the old code, as I pointed out, this is not the way to do it as you suggested, I am currently changing away from that as you saw in the code I placed on pastebin (however this doesn't allow for the restart effect): http://pastebin.com/SGkB2Rju

(By the way, would it be easier if I provided you with all of the code so you could see the delegates at work?)

Hello, sorry that it's taken me 2 days to get back to you. You can thank <unnamed British ISP> for that...

Delegates; they will execute on the same thread you call them from unless you tell it otherwise (using BeginInvoke). Delegates are typically used as callback methods or Thread entry points (C++ function pointers).

With this knowledge, yes, you can reduce your resource usage considerably by not spawning thread after thread in your delegates :)

To explain your execution using delegates I start with Thread 1.

Thread 1 creates a Thread 2 and hits Start, passing it the delegate to MethodTwo() as a callback.
Thread 1 carries on doing its thing and Thread 2 starts processing.

Thread 2 calls invoke on your delegate. MethodTwo() is now executing on Thread 2, not Thread 1. Your execution path in your initial method of Thread 2 is halted until it returns from MethodTwo() (it is a blocking call)

You say you want button 1 to start and button 2 to stop. But do you mean halt the process mid-way or simply stop checking if it's time to read a new score table?

In the first instance, I wouldn't consider that good design. You really should avoid aborting threads part way through. If you believe you have sections that could safely be aborted, precede them with a check to see if the user wants to cancel and then safely exit the thread.

In the second case, if you're going to BusyWait, make sure you have a cancellation flag that you loop around. If that gets set true, exit the thread (return from the method)
If you're using Mutex, use the cancellation token. If you're going timer event driven, simply stop the timer.

I don't think I need to see the full code, you seem more than capable of working out the code for yourself, I'm just trying to nudge you in the right direction and give advice about threading :)

Oh, nearly forgot, the difference between Invoke and BeginInvoke is that BeginInvoke is an asynchronous call that executes on a ThreadPool thread. You must also call EndInvoke to finish the call.

The best place for information regarding delegates is the MSDN library. Microsoft have some pretty good documentation on .NET :) Google 'Delegates c# MSDN' and you should be met with chapters of information on delegates and usage. If you understand function pointers in C/C++ then just apply that concept to delegates, only delegates are also type safe.

Eh don't worry about it, now I am taking my own time to reply (busy and sick).

Anyway over the last weekend I actually found the fault for the memory leak. It wasn't my threads in one bit, it was the cURl library I was using. Ended up moving the whole function to its own class and then when it was finished I disposed of it (and initiating the automated garbage collector seems to leave everything else alone).

As for the buttons, I guess I should correct what I meant to say. Button 1 would start the thread (the readin process), and then button 2 would pause it (so they could hit button 1 again to resume). The thread wouldn't actually be killed until the program closes (which I assume it does fine on its own? Somehow I feel that's the wrong thing to say).

But I assume all I have to do is pass in like a boolean, where I have a loop inside another loop. One pretty much starts and stops with the thread, the other works off a boolean variable I could change ... if I am using a BusyWait concept (I am going to stick to this for now, as it's going to be getting the test it's been waiting for and I don't want it laying in parts).

And I think I am grasping delegates more and more. The Invokes pretty much say, execute that on this thread when you Invoke (or something like that). I was looking over my inital posted code and I realized I was doing something like this with Form1 (to access the windows form items). Still trying to fully understand it (like how to invoke within a thread, but it looks like you wrote something along those lines, I'll re-read it and see if I truly understand it.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.