Multithreading Throws Exceptions in Revit 2015

I have received several cases lately dealing with add-ins that have been working fine in previous versions of Revit and now throw various exceptions after migration to Revit 2015.

Similar issues were also raised in the Revit API discussion forum, e.g. exploring a
Revit 2015 exception with a CustomExporter.

In all of the cases so far, these problems were due to attempts to access the Revit API from a multi-threaded context.

As the Revit API documentation clearly states, multi-treaded use of the Revit API is not supported and never has been.

This is spelled out in those very words in the
Revit API developers guide.

If you search it for the single word “thread”, the first hit displayed is the section on
Deployment Options:

Deployment Options

The Autodesk Revit API supports in-process DLLs only. This means that your API application will be compiled as a DLL loaded into the Autodesk Revit process. The Autodesk Revit API supports single threaded access only. This means that your API…

Let’s look at two recent cases dealing with this:

Question 1: I am migrating my Revit add-in from Revit 2014 project to Revit 2015.

In it, I loop through the parameters of an element, and check the parameter StorageType.
If it’s Double, e.g., I call AsDouble to retrieve the parameter value.

This code worked fine in Revit 2013 and 2014.
In 2015, it throws an exception error and exits Revit.

Many other properties on the parameter also generate the same exception, e.g. HasValue, IsReadOnly and so on.

If I run in Debug mode, an AccessViolationException is thrown:

AccessViolationException

Running my add-in program directly from Revit in release mode causes an unrecoverable error:

Unrecoverable error

After that, Revit closes:

Error report

My add-in calls a method that runs in its own background worker process.

As said, this code worked fine for several years, e.g. in Revit 2012 and 2013, and the problem only appears in Revit 2015.

Question 2: Having previously developed a custom add-in for Revit 2013 and 2014, I am now testing a forthcoming release for Revit 2015 compatibility. After changing references to the 2015 versions of RevitAPI.dll and RevitAPIUI.dll and the target framework to .NET 4.5, I attempted to run the program via the 2015 Add-in Manager. It loaded without any issues, but when it attempted to execute code pertaining to a background worker class (which updates a UI progress bar) Revit crashed immediately.

Are add-ins no longer able to execute background worker classes on a separate thread from the main Revit UI thread?
If so, this seems like a significant change.

Essentially, I am trying to get a progress bar to update while performing time-consuming calculations based on elements in the Revit model (no transactions, just collecting and reading parameter values).

Answer: You are perfectly correct in your assessment of the problem:

Revit add-ins are not allowed to access the Revit API from separate threads, only from the main Revit UI thread.

However, this is not a significant change, and not even a change at all.

This has always been the case.

For better protection of the add-ins developers and their users, it is now more strictly enforced.

Please look at the
Revit API developers guide and
its section on
Deployment Options quoted
above.

If you were previously accessing the Revit API from a separate thread, you and your users were at great risk.

If all you are doing in the separate thread is display a progress bar, with no Revit API access at all, there should be no problem.

Revit API access is however limited to the main thread.

This very topic was explicitly discussed on The Building Coder three years ago, in a post with a title that says it all:

no multithreading in Revit
.

Regarding the task at hand, you will have to collect all the required Revit element data in one go beforehand, from the main execution thread.

Once you have it, you can happily launch your processing and progress bar in a separate thread, as long as you make no more Revit API calls in it.

Response: Thanks for your feedback. The challenge I was facing is that it is precisely the Revit API calls (which consist of filtered element collectors and get parameter values) that consume the vast majority of operation time, i.e. ca. 30 seconds for a moderately sized Revit model. Hence, I chose to introduce a background worker that would enable me to update a progress bar during the operation, so that our users would know if there was time to go get a coffee.

I found your progress bar example in the
ADN Revit MEP sample AdnRme quite
helpful insofar as you were able to implement UI updates without resorting to multithreading via a call to the System.Windows.Forms.Application.DoEvents method. I tried moving my earlier code outside the background worker and replacing each instance of


bw.ReportProgress(progress, notification);

with


reportProgress(progress, notification);

where the associated functions are defined as follows:


bw.ProgressChanged += new ProgressChangedEventHandler(
delegate(object o, ProgressChangedEventArgs args)
{
bProg.Value = args.ProgressPercentage;
labelPerc.Text = args.ProgressPercentage + "%";
labelLoading.Text = args.UserState.ToString();
});
void reportProgress(int progressvalue, string notification)
{
bProg.Value = progressvalue;
labelPerc.Text = progressvalue + "%";
labelLoading.Text = notification;
System.Windows.Forms.Application.DoEvents();
}

And the good news is… with this change my application seems to work perfectly well in Revit 2015!

The only noticeable difference is that I loose UI control within my form while the time-consuming operations are taking place (except for that brief moment when the UI refresh takes place and users can access events like click, resize, drag, et. al.). This isn’t a problem for me, as I don’t need users to do any UI work while my application is performing these operations. Are you aware of any potential pitfalls of this DoEvents call? If not, I’d say this is a great workaround!

So please be aware that multi-threaded usage might be causing unexpected new exceptions in your code that seemed to work fine in previous versions.

I hope you can appreciate and be grateful that you are now forced to rectify the previous illegal API usage.

Sorry for the additional work this might be causing.

It is for your own good :-)


Comments

13 responses to “Multithreading Throws Exceptions in Revit 2015”

  1. Arjen de Pater Avatar
    Arjen de Pater

    Hi Jeremy,
    Also in a single threaded context Revit 2015 will raise various exceptions where 2014 didn’t.
    1. Subscribe to the UIControlledApplication.ViewActivated event;
    2. Start Revit 2015 and open f.i. 10 3D views in tile mode; (My model had linked models, maybe this matters)
    3. Switch rapidly the ‘Visual Style’ of each view;
    After circa 10 times, Revit will crash.
    Arjen

  2. Dear Arjen,
    Oh dear me, that sounds rather worrying. Could you please submit and ADN case for it as well? I would definitely like to ask the development team to have a look at that.
    Is it also possible to reproduce that programmatically? Could you send me a ready-to-compile add-in plus solution to demonstrate the behaviour?
    Thank you!
    Cheers, Jeremy.

  3. Adrian Hodos Avatar
    Adrian Hodos

    How about stepping out of the dark ages and make the API thread safe ? Everybody has a machine with at least 2 cores these days. Your users will thank you. Your developers will thank you even more. The light, you have to see the light, damn it :)

  4. Dear Adrian,
    Yes, absolutely. Great suggestion. Please refer to this recent discussion on the topic for more details:
    http://thebuildingcoder.typepad.com/blog/2014/02/different-revit-api-aspects-and-features.html
    http://thebuildingcoder.typepad.com/blog/2014/02/more-on-revit-api-aspects-and-features.html#6
    Cheers, Jeremy.

  5. Corbin Avatar
    Corbin

    Hello:
    I was wondering if the DirectX 12 API will effectively enhance overall performance in Revit. Sorry if I sound ignorant in any way. I do not know about any programming or its framework.
    I hope DirectX 12 will help utilize all new high-end hardware capabilities to there possible potential. Because, most of the time when there is a big Revit file when waiting while it generates/processes. I noticed that all my hardware isn’t running at desired higher levels that could potentially make the process much faster. Therefore, my point is that the hardware is being under utilized… I see this for all programs/games not just Revit.
    If DirectX12 API is going to implemented with Autodesk products. When do you think it will be released? I know the official DirectX12 will be released by the end of this year. Also, will this only support Windows 8+?
    (The hardware I am referring to is: CPU, GPU, (HDD/SDD/mSATA) read/write speeds, RAM I/O)
    My ‘Uber’ Laptop Specs:
    Brand/Name: MSI GT70 Dominator Pro-1039
    Processor: 4th Gen Intel Core™ i7-4940MX Processor Extreme Edition (8M Cache, 4 Cores, 4.00GHz)
    HDD Drives: 3 x 128GB mSATA (Super RAID 0 v.2) + 1TB 7200 RPM Hard Drive (For Storage)
    Graphics: NVIDIA GeForce GTX 880M GDDR5 (8.0GB) + Intel® HD Graphics 4600
    Memory: 32GB DDR3 1600MHz (Four 204Pin SODIMM Sockets)
    Price: $ 3,999.00 U.S. Dollars
    Comments:
    – Will multiple mSATA/SSD (as Super Raid 0) improve performance when working on a Central file (disregard network usage)? So far I haven’t seen to much of a difference when compared to regular HDD except when opening/saving files.
    – What will be the best stripe size to set the RAID 0 to? I am curious about how this will affect large Central files.
    – What kind of RAM provides the most performance. Right now I have 32GB of DR3 1600MHz that came with the laptop. I am not sure what brand it is. Thinking about trying out Corsair Vengence Pro DDR3 2133 MHz 4 x 8GB. Do you think RAM performance is a large factor to speed?
    I know its not a ‘workstation’ certified computer, because it contains a gaming video card. However, this thing is a monster and is actually much faster than than any computer or certified ‘workstation’ I have ever used. I am very supprised when I see any wait time while views/tasks generate or process, because all of the hardware is barely being utlized… Not once have I seen anything reach 100% performance capacity except when I was upgrading 5 files to Revit 2015 and had VMware Workstation running all at once.
    Overall, I love this laptop very much when, because I hate any possible lag or sluggish performance. I wish I had one of these at the office too..

  6. Dear Corbin,
    Sorry if I sound ignorant, but I have absolutely no idea.
    I deal with the Revit API, not installation or hardware.
    Cheers, Jeremy.

  7. Jeremy,
    We came across the same issue described in Question 2 and submitted a ticket in ADN, the case NO is :10402895 (a project is attached in the ticket)
    I tried the workaround you suggested using Application.DoEvents() but the problem is the form has to be modaless which is not what we want.
    Update Revit parameter in the background while running windows form with progress bar will not crash Revit before 2014. Any solid workaround for providing status update in the front while call time-consuming API at the same time?

  8. Dear Limin,
    You absolutely cannot safely perform any modification on the Revit database or use the Revit API in any way whatsoever. even for read-only purposes, except in a valid Revit API context:
    Here is the final word on that:
    http://thebuildingcoder.typepad.com/blog/2014/11/the-revit-api-is-never-ever-thread-safe.html
    A valid Revit API context is provided by Revit by a callback function, e.g. execution of an external command or in an event handler.
    The workaround is clear and simple: implement an external event.
    As far as I know, this has also been clearly communicated to you in the ADN case you raised.
    Cheers, Jeremy.

  9. Jeremy,
    Thanks for the explanation. But the workaround uses modeless form, that means user still can make change through Revit UI while .net API is called,isn’t that less protected?
    Did you run the project I attached with my ticket? as you can see, it’s not multi-thread of Revit, it’s just one thread of Revit running in the background while a modal windows form update status in the front. I’m surprised Revit will crash in such a case since 2015.

  10. Dear Limin,
    The Revit can never be used from a separate thread, as explained fully in the blog post listed above.
    Cheers, Jeremy.

  11. Hi, Jeremy,
    I figured out a workaround to solve the problem.
    Here is the source code I upload:
    https://github.com/lotusinriver/MonitorProgressRevit
    Update progress from a Modal dialog while call Revit API
    Hope it helps other used to use BackgroundWorker to implement this feature.
    Cheers

  12. Dear Limin,
    Thank you for your sample.
    I just took a look at it.
    Congratulations on achieving maximum confusion with a minimum of effort.
    For instance, you do not provide an add-in manifest, so I had to write it myself.
    The solution name is MonitorProgressRevit, the project name is MonitorProgress.vbproj, and the resulting .NET assembly DLL is MonitorProgess.dll, with one ‘r’ missing.
    It took quite a few attempts to figure all this out…
    Still working on it, though…
    Cheers, Jeremy.

  13. Dear Limin,
    I finally got it compiled and tested successfully on Revit 2015.
    I created a pull request to update your repository with my changes.
    Can you pull them, please?
    I will happily publish this. Looks useful.
    Thank you!
    Cheers, Jeremy.

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading