Hello Erik,
I appreciate you being cautious when experimenting with multithreading in the Revit API. It can only pay off. However, practically nothing you do (short of running separate processes) can guarantee you always a successful execution no matter what you do and how careful you are. I did understand your intention very well. You try to read properties of elements you have collected in a collection. You do it with parallel execution. It sounds like it ought to be safe, and it might, as long as you read thread-safe data, and the end user is doing nothing, and there is no other external application installed with Revit, including the ones we ship Revit with. And that is rather hard to guarantee, I am afraid.
Your idea about using Document.IsModifiable may sound like one way to mitigate problems, but it is not. For one, the method itself is not thread-safe, but even if it were (and it would not be very difficult to make it if we wanted to), it would still not be an atomic operation, thus the result you get from calling it may not reflect the state of the property at the time the result is delivered to you. In other words: You cannot trust the value of IsModifiable if you are looking at it from other then the main thread. This is in fact similar to reading any non-thread-local value from multiple treads. Unless you put locks around it, you cannot guarantee that the read operation returns a current value.
Again, I understand well that you are not trying to read values while modifying the model at the same time. You are just reading. However, even just reading is not safe unless you are also completely in control of writing. And this only applies generally – it does not always apply to every reading in Revit. Let’s assume that you are in control of writing. Let’s say you are executing your external command in a read-only transaction mode, or in manual mode but without a transaction open. Then you are virtually guaranteed the document is in read-only state. However, it does not mean there will be no changes to the memory we need for the model. When a model is opened in Revit, we do not load it in all at once. We only load the parts we need to know about, which include certain information about each element, but not all data associated with every element. If you happen to read only the data from the top-level tier, you would be safe. However, if you happen to read data that require the element to be fully loaded in (we call it “expanding an element”), you may get into trouble. This operation will require memory to get allocated and I am afraid that element expansion may not be completely safe when it is triggered from multiple threads at the same time.
I might have gone a bit too technical, but my main point was to elaborate on my previous statement, which was that One cannot be ever thread-safe in the Revit API even if only reading from the model.
Arnošt Löbel