0

I have time-consuming function and I want to give the user an opportunity to stop it by clicking a button in the UI when he notices that it takes too long. How can I do this?

Ry-
  • 218,210
  • 55
  • 464
  • 476
stanwar
  • 181
  • 1
  • 8

5 Answers5

3

You can use BackgroundWorker class to run time and resource consuming stuff on other thread, and use its CancelAsync method, to request (it's not immediate execution) cancelation of the other thread.

For concrete example on how to implement that, can have a look on accepted answer in this question:

How to wait for a BackgroundWorker to cancel?

Community
  • 1
  • 1
Tigran
  • 61,654
  • 8
  • 86
  • 123
1

First of all, you need to run the time-consuming function in a thread separate from the main thread. Otherwise the UI will stop responding.

Then you need to have a static variable or a shared instance where the UI can set a flag indicating that the time-consuming function should stop.

Finally, the time-consuming function should regular check the flag and stop processing if it is set.

The BackgroundWorker class implements this pattern and solves a few other requirements as well (such as the inter-thread communication and the progress reporting).

Codo
  • 75,595
  • 17
  • 168
  • 206
1

Lets say your time-consuming method is called MyTimeConsumingMethod.

void MyTimeConsumingMethod()
{
       //Do stuff
}

Put globally a thread:

Thread t; 

Put in your Form_Load()

t = new Thread(new ThreadStart(MyTimeConsumingMethod));
t.Start();

And on button press:

t.Abort();
Thanatos
  • 1,176
  • 8
  • 18
0

Here's an example

bool _cancel = false;
private void count()
{
    _cancel = false;
    new System.Threading.Thread(delegate()
    {
        for (int i = 0; i < 100000; i++)
        {
            if (_cancel)
                break;

            Console.WriteLine(i);
        }
    }).Start();
}

private void button1_Click(object sender, EventArgs e)
{
    _cancel = true;
}
denied66
  • 644
  • 7
  • 18
  • 1
    It's not really an option to *not* run it in a different thread. If it's running in the UI thread you can't click the button to cancel execution, which is the requirement. – Servy Aug 27 '12 at 18:13
  • I agree. I'm assuming the OP already has it setup to run on a different thread that's why I just gave him the example on how to modify the already existing method that he/she has in place. – denied66 Aug 27 '12 at 18:17
  • Updated the post to remove the "assuming" 'variable' – denied66 Aug 27 '12 at 18:21
  • Pretty sure `_cancel` will need to be marked `volatile`, or wrapped in a `lock` block, to ensure the proper memory barriers are added. – Servy Aug 27 '12 at 18:22
  • Have you tried it ? Because personally I don't have any issues running the above code. Also, why do you need to use a lock statement if only one thread is going to be accessing the variable. – denied66 Aug 27 '12 at 19:42
  • You don't need to use a `lock` here, but you need to do something to introduce a memory barrier so that the threads know not to rely on locally cached values because the variable could be modified in another thread. There are two ways to do this, either mark it as `volatile ` or use a `lock`, which has the additional affect of applying these memory barriers. It won't always break without either, but it might break if you don't do one or the other. – Servy Aug 27 '12 at 19:50
  • For cases like the ones you mention then yes a lock is needed. But since the OP didn't request/or specified that he/she is using multiple threads for this I don't think putting extra information in a post will do any good. It's the same as saying that anonymous methods shouldn't be used in the example above because they are not supported by .net version prior to v2. – denied66 Aug 27 '12 at 19:55
  • but you are accessing `_cancel` from multiple threads. One thread (the UI thread) is setting it, and a background thread is reading it. – Servy Aug 27 '12 at 19:59
  • The button from the UI is supposed to stop the thread (based on what the OP requested). Since don't have any indication if the thread actually resumes/restarts or not at any point then we are basically discussing 'what if' cases. But since I don't think SO likes long discussions in the comments, I'll just move the bool out of the thread just so we can end this discussion. – denied66 Aug 27 '12 at 20:04
  • What do you mean "what if cases"? You are 100% sure that you will be accessing the same variable from multiple threads. The problem is that when you write to `_cancel` in the UI thread it can just change the cache, and not the actual location in memory (for a long while) so the `if (_cancel)` check in the background thread won't "see" the changed value; it will think it's still `false` until the cached value is saved back into memory, and the cache of the background thread pulls in the new value from memory. If you use `volatile ` it knows not to cache it. – Servy Aug 27 '12 at 20:07
0

Try running it on a Background Worker.

This Gives a good example of how to use it.

Then you can call

Worker.CancelAsync(); 

when the user wants to cancel the operation

CSharpDev
  • 869
  • 1
  • 13
  • 22