Bogey Bogey - 24 days ago 6
C# Question

Concurrency of modifying a Roslyn workspace? How does Visual studio do it?

probably a stupid question, but: Is there any way to reliable apply changes to a Roslyn workspace concurrently? And if not, what is the best practice to ensure it's done in correct order?

Example: Say you have some solution loaded into a Workspace, and have a basic function that will add a new project to the solution:

private Workspace _workspace;

// This is not thread-safe, right?
void AddProject()
var project = _workspace.CurrentSolution.AddProject(/* ... */);

First question: Correct me if wrong, but I think AddProject would not be thread-safe, is that correct?

For example, lets say you want to add to new projects concurrently. So you call AddProject() twice concurrently.

My understanding is there is a race condition, and you might end up with both projects added (if one of the calls completes TryApplyChanges before the other call reaches _workspace.CurrentSolution), or only one of the projects added (if both calls have reached _worksapce.CurrentSolution before either has executed TryApplyChanges).

Second question: If my understanding is correct, then is there any best way to avoid these concurrency issues? I suppose the only real way would be to schedule/execute each modification sequentually, right?

How does Visual Studio, for example, do this.. Are modifications to the Workspace e.g. only done on the Dispatcher?


Answer Source

The underlying code is thread-safe, but your usage is not.

TryApplyChanges() will return false if the solution changed in the meantime. If that happens, you need to try the changes again (starting from the new CurrentSolution).

Basically, you need to write

Solution changed;
do {
  changed = _workspace.CurrentSolution....();
} while (_workspace.TryApplyChanges(changed);

This is called a compare-and-swap loop; see my blog for more details.