[
Advertise | Submit Code | About us | Contact us | Link us
]
Go!
Membership Services
Login
Register

Home
C# General

General

C# Language

Design & Architecture

Algorithms

Database

Security

Active Directory

COM Interop

Remoting
C# Windows Forms

General

Combo and List boxes

Miscellaneous Controls

Button Controls

Edit Controls
Cutting Edge

ASP.NET 2.0

Visual Studio 2005

Windows Longhorn

SQL Server 2005
C# Multimedia and GDI+

General

DirectX

GDI+

Audio
Internet & Web

General

Images and multimedia

Database

Utilities

Security

ASP.NET Controls

Design and Architecture

Webservices
.NET

General

Design & Architecture

Algorithms

Database

Security

Active Directory

COM Interop

Remoting

ADO.NET

XML.NET

Tools

Enterprise

IDE
Visual Basic .NET

VB.NET General

VB.NET Controls
General Reading

.NET Books Review

Product Showcase

Book Chapters

Business Design & Strategy
Community

Discuss

Job Board

Discussion

CodeXchange
DeveloperLand

Advertise

Submit Code

About us

Contact us

Link us
Miscellaneous

Favorite Links

Downloads

Programming Sites

Top Stories
Regular Expressions

E-Mail

Date/Time
Home > C# General > General
Lengthy Operations on Single Thread in .NET Application
Posted by on Tuesday, October 19, 2004 (EST)

Desktop applications are usually single-threaded. Sometimes it is, however, inevitable to perform some long lasting operations like processing large XMLs. This leads to a common problem: how such long lasting operations should be managed?

This article has been viewed: 7,326 times
Technology: General.

Contents

The problem

Desktop applications are usually single-threaded. Sometimes it is, however, inevitable to perform some long lasting operations like processing large XMLs. This leads to a common problem: how such long lasting operations should be managed?

If you try to search for an answer, you'll find that there are two possibilities:

  • perform lengthy operation on a new thread
  • perform lengthy operation on the same thread
The former possibility involves threading issues such as synchronizing threads and updating the GUI from other threads. However, I've found that this possibility is preferred over the latter. There is a main reason for this: the lengthy operation cannot be easily interrupted in a single-thread application. Below I will try to show you that this problem can be solved.

Top Go to Table of Contents

The solution

The solution I suggest is rather simple. You have to force the lengthy operation to scan the main message loop of the application (Application.DoEvents). This way you can inform the lengthy operation that it should stop using some external information. In the example below, the lengthy operation is controlled by CanContinue variable. The variable value is changed upon the user interaction. Note that the ButtonStop_Click event is executed from within the LengthyOperation indirectly - it is the Application.DoEvents that dispatches all pending Win32 events, in our case it forces the button click event to be executed.
public bool CanContinue = true;
public void LengthyOperation()
{
 while ( true )
 {  
  // check
  if ( !CanContinue ) return;
  
  // force all pending messages to be dispatched
  Application.DoEvents();
  
  // do the lengthy job
  ...
 }
}
public void ButtonStart_Click( object sender, EventArgs e )
{
 LengthyOperation();
}
public void ButtonStop_Click( object sender, EventArgs e )
{
 CanContinue = false;
}

Top Go to Table of Contents

New problems appear

The above solution seems to be correct until we realize that this is not only a pending button-click event that is executed by Application.DoEvents. In fact, all pending Win32 events are executed by Application.DoEvents call. This causes two new problems to appear:
  • if Application.DoEvents causes another lengthy operation to invoke then the interruption-problem reappears. In particular cases it could even lead to infinite recursion:
     public void ButtonStart_Click( object sender, EventArgs e )
     {
      LengthyOperation();
     }
     
     public void ButtonStop_Click( object sender, EventArgs e )
     {
      // instead of stopping the operation
      // risk an infinite recursion
      LengthyOperation();
     }
     
  • if the user tries to close the main application window (by pressing the x in the upper-right corner of the window) during the lengthy operation an event will occur in the application's main loop. This event will also be handled by Application.DoEvents. This could be a disaster! Instead of interrupting the lengthy operation, the user could shut the application down.

Top Go to Table of Contents

New problems go away

Top Go to Table of Contents

Careness to the rescue

First one of above problems can be avoided. All you have to do is to not to allow the user to press "dangerous" buttons or menu items so that he is unable to invoke new operations. For example:
public void ButtonStart_Click( object sender, EventArgs e )
{
 // do not let the user to start another instance of the operation
 // while one is in progress
 ButtonStart.Enabled = false;
 
 LengthyOperation();
 // it is safe to start new operation now
 ButtonStart.Enabled = true;
}

Top Go to Table of Contents

Reflection to the rescue

The second problem is more subtle. The lengthy operation could be invoked any context so at first glace there's no simple way to stop Application.DoEvents to process events of the main form (and prevent it from closing the main form). Note, however that when Application.DoEvents is invoked from within the lengthy operation then the LengthyOperation's frame is still on the stack! And we can examine the stack using the reflection! This is then how we prevent the main form from beeing closed by careless user (and Application.DoEvents): when the main form is about to be closed we check the stack trace and look for methods that are marked as uninterruptable. If at least one such method is found then we are sure that an operation that should not be interrupted is in progress. We then cancel the closing.
public class UnInterruptable : Attribute {}
// -------------------------------------------------------------------------
public static bool IsInterruptionPossible()
{
 StackTrace st = new StackTrace();
 for ( int i=0; i<st.FrameCount; i++ )
 {
  StackFrame sf = st.GetFrame(i);
  MethodBase mb = sf.GetMethod();
  foreach ( Attribute a in mb.GetCustomAttributes(true) )
  {
   if ( a is UnInterruptable )
    return false;
  }
 }      
 
 return true;
}
// -------------------------------------------------------------------------
public bool CanContinue = true;
// mark the operation as uninterruptable
[UnInterruptable()]
public void LengthyOperation()
{
 while ( true )
 {  
  // check
  if ( !CanContinue ) return;
  
  // force all pending messages to be dispatched
  Application.DoEvents();
  
  // do the lengthy job
  ...
 }
}
public void ButtonStart_Click( object sender, EventArgs e )
{
 LengthyOperation();
}
public void ButtonStop_Click( object sender, EventArgs e )
{
 CanContinue = false;
}
// -------------------------------------------------------------------------
public MainForm_Closing( object sender, , System.ComponentModel.CancelEventArgs e)
{
 // check if there are some uninterruptable operations in progress
 if ( !IsInterruptionPossible() )
 {
  e.Cancel = true;
  return;
 } 
}

Top Go to Table of Contents

Conclusions

In this article I've shown how the lengthy operations can be handled in a .NET application. I've also shown how the stack trace can be examined to find any specific methods. I hope this article will be usable to the reader.

Top Go to Table of Contents

About Wiktor Zychla

Click here if you want to know more about .

Other articles that may interest you

  • Write a Word Add-In – Part 0
  • Write a Word Add-In – Part I
  • Lengthy Operations on Single Thread in .NET Application
  • Learning Draughts
  • Exceptions and Performance
  • Average Rating :

    Discussion Forums
    Got a programming related question? Hopefully someone has the answer... Want to help out other developers? Visit our discussion forums.

    Sponsored by:

    New Articles

  • Exceptions and Performance
    Almost every time exceptions are mentioned in mailing lists and newsgroups, people say they're really expensive.Let's examine that claim, shall we?

  • Creating multilingual websites - Part 1
    Extend the existing globalization capabilities of .NET to create flexible and powerful multilingual web sites. First, create a custom ResourceManager, and then create custom localized-capable server controls to easily deploy multilingual functionality.

  • Parameter passing in C#
    Many people have become fairly confused about how parameters are passed in C#, particularly with regard to reference types. This page should help to clear up some of that confusion

  • Most Popular Articles

  • LDAP, IIS and WinNT Directory Services
    This article explains how to use .NET Directory Services to retrieve and search directory objects, create new directory objects and edit or delete existing directory objects. Describes Active Directory Application Mode (ADAM) and how to use the IIS, WinNT and LDAP directory (ADSI) provider.

  • An in-depth look at WMI and instrumentation, Part II
    WMI stands for Windows Management Instrumentation and, as the name indicates, is about managing your IT infrastructure this article is the second part of a two-part series.

  • An in-depth look at WMI and instrumentation, Part I
    WMI stands for Windows Management Instrumentation and, as the name indicates, is about managing your IT infrastructure this article provides an in-depth look at WMI and MOM 2005

  • New Books

  • Murach's ASP.NET 2.0 Upgrader's Guide: VB Edition
    What’s new and how to use it! That’s what this book delivers if you’re a VB developer who’s interested in upgrading from ASP.NET 1.x to ASP.NET 2.0.

  • C# in easy steps
    Learn to program with Microsoft’s premier programming language. No previous programming knowledge is assumed. With numerous easy-to-follow examples, this title explains the essentials of object-oriented programming with C#.

  • Murach's ASP.NET web programming with VB.NET
    Murach's ASP.NET web programming with VB.NET by Doug Lowe and Anne Prince is a in depth training and reference book for ASP.NET programming using VB.NET. The book builds upon Murach's previous books and covers more advanced concepts for programming ASP.NET pages.

  • Got Code?

    if you have any article , source code , or anything else you'd like to share with this community that you think others might find useful, please submit it here and we will gladly make it available on this site. submit@developerland.com.
    Partners

    All articles are copyrighted by their individual authors unless otherwise specified , everything else Copyright ©2004-2006 DeveloperLand