?
Solved

Delegates and ASync Callback - How to Cancel

Posted on 2007-04-02
9
Medium Priority
?
1,400 Views
Last Modified: 2008-02-01
Experts,
     I'm having issues cancelling some threads (up to 8 running at the same time). When I first started my project, I didn't give any thought to being able to cancel the threads I create with my application, however I am thinking about it now. Here is my previous post that I used to create my threads: http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_22424243.html
    If anyone can tell me how I can cancel the threads created (they have an async callback method), I would appreciate it. I've got to give my users the option to stop testing if they messed something up...

Thanks in advance,
Yeavis
0
Comment
Question by:Yeavis
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 4
9 Comments
 
LVL 8

Accepted Solution

by:
Rytmis earned 2000 total points
ID: 18838304
This is the way I've done it:

- GUI starts a background worker thread
- Worker starts
- Worker does some processing, calls SomeCallback on the GUI every now and then
- User clicks on "Cancel button" -- this sets a flag, say "CancelProcessing" on the GUI
- Worker does more processing, calls SomeCallback. One of the arguments for SomeCallback is a SomeEventArgs object with a member variable "Cancel".
- SomeCallback notices that CancelProcessing was set before, and sets Cancel on the SomeEventArgs to true
- Worker notices that the call to SomeCallback changed SomeEventArgs.Cancel to true, cleans up and quits

I'm sure I didn't explain it very well, so please ask if I left something out. :)
0
 
LVL 8

Expert Comment

by:Rytmis
ID: 18838517
Taking a look at the other thread you've participated in, you seem to be using asynchronous delegate invocations instead of Thread/ThreadStart, so I'm not sure it's even possible to stop execution in that case. :/
0
 

Author Comment

by:Yeavis
ID: 18838691
I found this on MSDN, and it fits with what I'm doing... however I am not sure how to implement the cancel functionality like they did. Any help would be appreciated..  http://msdn2.microsoft.com/en-us/library/bz33kx67.aspx
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 8

Expert Comment

by:Rytmis
ID: 18850046
If I understand correctly, what the code in the article you refer to does is it cancels *pending* operations, not *running* operations. As far as I can tell, you can't cancel asynchronous method calls, you'd have to move to full-blown threads that periodically fire an event, and the subscribers to that event can then set a cancel flag.
0
 

Author Comment

by:Yeavis
ID: 18850658
Could you please show me how I would do that? If possible could you use the link I provided with that code? I'm rather new too threading so any help would be appreciated.
0
 
LVL 8

Expert Comment

by:Rytmis
ID: 18850702
I'll see what I can do after work, but if someone else wishes to shed light on the issue while I'm gone, go right ahead. :)
0
 
LVL 8

Expert Comment

by:Rytmis
ID: 18851385
Here's a simplistic example with a thread that increments a counter and sleeps for half a second each time. Written for .NET 2.0, so if you're running 1.1 you will have to combine these two partial classes into one class:

MainForm.designer.cs:

namespace Sandbox
{
      partial class MainForm
      {
            /// <summary>
            /// Designer variable used to keep track of non-visual components.
            /// </summary>
            private System.ComponentModel.IContainer components = null;
            
            /// <summary>
            /// Disposes resources used by the form.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                  if (disposing) {
                        if (components != null) {
                              components.Dispose();
                        }
                  }
                  base.Dispose(disposing);
            }
            
            /// <summary>
            /// This method is required for Windows Forms designer support.
            /// Do not change the method contents inside the source code editor. The Forms designer might
            /// not be able to load this method if it was changed manually.
            /// </summary>
            private void InitializeComponent()
            {
                  this.progressBar1 = new System.Windows.Forms.ProgressBar();
                  this.button1 = new System.Windows.Forms.Button();
                  this.button2 = new System.Windows.Forms.Button();
                  this.SuspendLayout();
                  //
                  // progressBar1
                  //
                  this.progressBar1.Location = new System.Drawing.Point(26, 37);
                  this.progressBar1.Maximum = 120;
                  this.progressBar1.Name = "progressBar1";
                  this.progressBar1.Size = new System.Drawing.Size(235, 23);
                  this.progressBar1.Step = 1;
                  this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
                  this.progressBar1.TabIndex = 0;
                  //
                  // button1
                  //
                  this.button1.Location = new System.Drawing.Point(26, 95);
                  this.button1.Name = "button1";
                  this.button1.Size = new System.Drawing.Size(130, 23);
                  this.button1.TabIndex = 1;
                  this.button1.Text = "Start a long operation";
                  this.button1.UseVisualStyleBackColor = true;
                  this.button1.Click += new System.EventHandler(this.Button1Click);
                  //
                  // button2
                  //
                  this.button2.Enabled = false;
                  this.button2.Location = new System.Drawing.Point(186, 95);
                  this.button2.Name = "button2";
                  this.button2.Size = new System.Drawing.Size(75, 23);
                  this.button2.TabIndex = 2;
                  this.button2.Text = "Cancel";
                  this.button2.UseVisualStyleBackColor = true;
                  this.button2.Click += new System.EventHandler(this.Button2Click);
                  //
                  // MainForm
                  //
                  this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
                  this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                  this.ClientSize = new System.Drawing.Size(292, 273);
                  this.Controls.Add(this.button2);
                  this.Controls.Add(this.button1);
                  this.Controls.Add(this.progressBar1);
                  this.Name = "MainForm";
                  this.Text = "Sandbox";
                  this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainFormFormClosing);
                  this.ResumeLayout(false);
            }
            private System.Windows.Forms.Button button2;
            private System.Windows.Forms.Button button1;
            private System.Windows.Forms.ProgressBar progressBar1;
      }
}


MainForm.cs:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using System.Reflection;

namespace Sandbox
{
      /// <summary>
      /// Description of MainForm.
      /// </summary>
      public partial class MainForm : Form
      {
            [STAThread]
            public static void Main(string[] args)
            {
                  Application.EnableVisualStyles();
                  Application.SetCompatibleTextRenderingDefault(false);
                  Application.Run(new MainForm());
            }
            
            private bool opCanceled = false;
            
            public MainForm()
            {
                  //
                  // The InitializeComponent() call is required for Windows Forms designer support.
                  //
                  InitializeComponent();
                  
                  //
                  // TODO: Add constructor code after the InitializeComponent() call.
                  //
            }
            
            public class ThreadEventArgs : EventArgs
            {
                  public int CurrentPos;
                  public bool Cancel;
            }
            
            public delegate void ThreadEventDelegate(ThreadEventArgs args);
            private delegate void ProgressBarSetterDelegate(int value);            
            
            void Button1Click(object sender, EventArgs e)
            {
                  ThreadEvent += new ThreadEventDelegate(UpdateGUI);
                  button2.Enabled = true;
                  new Thread(new ThreadStart(LongOperation)).Start();
            }
            
            void Button2Click(object sender, EventArgs e)
            {
                  this.opCanceled = true;
            }            
            
            void UpdateGUI(ThreadEventArgs args)
            {
                  if(InvokeRequired)
                        Invoke(new ProgressBarSetterDelegate(SetProgressBarValue), args.CurrentPos);
                  else
                        SetProgressBarValue(args.CurrentPos);

                  args.Cancel = this.opCanceled;
            }
            
            void SetProgressBarValue(int value)
            {
                  progressBar1.Value = value;
            }
            
            public event ThreadEventDelegate ThreadEvent;
            
            void LongOperation()
            {
                  for (int i = 1; i <= 120; i++)
                  {
                        ThreadEventArgs args = new ThreadEventArgs();
                        args.CurrentPos = i;
                        
                        if(ThreadEvent != null)
                              ThreadEvent(args);
                        
                        if(args.Cancel)
                              return;
                        
                        Thread.Sleep(500);
                  }
            }
            

            
            void MainFormFormClosing(object sender, FormClosingEventArgs e)
            {                  
                  this.opCanceled = true;
            }
      }
}

The way this works is LongOperation calls the ThreadEvent event, and any delegate subscribed to that event may set the Cancel flag on the ThreadEventArgs parameter. If the flag is set to true after the event has been raised, LongOperation returns.
0
 

Author Comment

by:Yeavis
ID: 18864143
Sorry for the delay... I will try this out and see if I can get it to work in my existing application. Thanks for the help...
0
 

Author Comment

by:Yeavis
ID: 18878838
Okay, I have tried your solution without any success. I probably should have been more clear about this, but I need to pass parameters to the starting thread as I did in the previous posting. Any help would be appreciated...
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: Najam
Having new technologies does not mean they will completely replace old components.  Recently I had to create WCF that will be called by VB6 component.  Here I will describe what steps one should follow while doing so, please feel free to post any qu…
The article shows the basic steps of integrating an HTML theme template into an ASP.NET MVC project
Do you want to know how to make a graph with Microsoft Access? First, create a query with the data for the chart. Then make a blank form and add a chart control. This video also shows how to change what data is displayed on the graph as well as form…
Have you created a query with information for a calendar? ... and then, abra-cadabra, the calendar is done?! I am going to show you how to make that happen. Visualize your data!  ... really see it To use the code to create a calendar from a q…
Suggested Courses
Course of the Month8 days, 18 hours left to enroll

764 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question