Silly, fun and useful things to do with Resolver One
  • HOME
  • About
  • Articles
  • Fun
  • Snippets
  • Disclaimer
  • Useful Links

Site by Voidspace

Email Michael

Download Resolver One

RSS Feed RSS Feed

Resolver Hacks contains information and code for doing fun and useful things with Resolver One. This site is created and maintained by Michael Foord, not by Resolver Systems. Please read the disclaimer before using any of the code on this site.

Site Built with rest2web

Creative Commons License

IronPython Wiki

IronPython in Action IronPython in Action

Recalculation and Threads

Note

This article is relevant for user-code that accesses external resources. If you aren't writing user code, or your code doesn't access any files or databases (etc) then you probably don't need to worry about it.

When you enter data into a cell, or edit any user code, Resolver recalculates the spreadsheet. In order to keep the user interface responsive, this recalculation happens on a background thread. Once the recalculation has finished, the grid is updated with all the new values. (You can tell if a recalculation is in progress, because the 'throbber' in the top right of Resolver will be spinning.)

If new input comes in whilst a recalculation is happening, the current one will be aborted and a new recalculation started with the latest data.

Of course, if your user code is doing something important when the calculation is aborted, unexpected things may happen.

Fortunately, there is something very easy you can do to make your code safe against this. For a summary, you can read this article on Threading and Aborting Threads with IronPython. You can also read about Python Exception Handling in the Python tutorial.

Recalculation threads are stopped by raising a ThreadAbortException inside them. However, this won't happen if your code is inside a finally block. So you can protect important parts of your code by putting it inside a finally block.

Suppose for example you wish to write some data to a file inside your user code. If the calculation is interupted you still want the file to be closed:

h = None
try:
    h = open(fileName, 'w')
    h.write(data)
finally:
    if h is not None:
        h.close()

Even if the calculation is aborted whilst writing to the file, the file will still be closed. (The check that h is not None is in case an exception occurs whilst trying to open the file.)

Alternatively, you culd put the whole write inside the finally:

try:
    # this is cheating of course
    pass
finally:
    h = open(fileName, 'w')
    h.write(data)
    h.close()

Be careful though, if you put an infinite loop inside the finally block, then it can't be terminated and the recalculation never completes!

Note

Because spreadsheets are calculated on their own thread, you can't use Windows Forms controls inside user code. This is because Windows Forms requires all controls to be on the same thread (the cotnrol thread).

There is currently no simple answer to this, but a solution will probably be provided at some point...

Some third party charting components (which are easy to integrate with Resolver by the way, but that is the subject of another article), act as Windows Forms controls. If you use them, make sure that the components you use aren't controls. Worst case, a cross-thread exception can happen inside Resolver rather than inside the user code.

Catching Exceptions

Because threads are killed by raising an exception (a ThreadAbortException). This exception can be caught by a normal try...except block, but by default is rereaised after the exception handling code has executed.

So bare excepts will 'temporarily' catch the abort exception:

try:
    doSomething()
except:
    # will catch a ThreadAbortException
    errorHandling()
# Which gets reraised here

and the same for the following:

try:
    doSomething()
except Exception, e:
    print 'An error occured: %s' % e

To avoid it, you could explicitly check for the ThreadAbortException and re-raise it.

For example, the second the block of code above could be rewritten as:

from System.Threading import ThreadAbortException

try:
    doSomething()
except ThreadAbortException:
    # A bare raise will re-raise the
    # last exception
    raise
except Exception, e:
    print 'An error occured: %s' % e

If you really want to cancel the abort, this is possible but not advised! (At best it will slow down calculations, at worst it will interact badly with the resolver internals.) I'm not going to show you how to do that, this may be Resolver Hacks - but there are limits...

The Current Directory

This has nothing to do with threads, but is till relevant to user code being executed in Resolver. Resolver runs as a single process, even when it has several documents open. This means that it has a single current directory that is shared between all documents. Even worse, the default behaviour for the Windows Forms OpenFileDialog is that it changes the current directory.

If your spreadsheet needs to access files, then you should always use absolute paths instead of relying on the current directory. Through the __file__ variable you have access to the path of the directory containing the current spreadsheet. Using this you can access files relative to the current spreadsheet. See Accessing Files for an example of how to do this.


Hosted by Webfaction

Return to Top

Last edited Mon Dec 10 14:30:31 2007.

Copyright ©2007 Michael Foord. All rights reserved. Design by Elemental Works. Logo by FuchsiaShock. Valid XHTML & CSS.

This work is licensed under a Creative Commons License.