Network surface multithreaded crash

I’m crashing my rhino when I throw in a Parallel.For() call in my c# script component, and I can’t figure out the cause.

What’s paralleled is the CreateNetworkSurface() method of Surface

Here’s my snippet for pattern. Abbreviated for legibility.
The code runs perfectly if I swap the parallel call with a foreach loop. With the parallel, it occasionally succeeds.

using System.Threading.Tasks;
using System.Linq;
// using more stuff

// omitted bunch of boilerplate codes

// my class object for parallel
protected class NWSrf{
    // omited some variables

    protected Curve[] crvs = null; // network curves
    internal NurbsSurface srf = null; // result surface

    public NWSrf(IEnumerable<Curve> c){
      crvs = new Curve[c.Count()];
      int i = 0;
      foreach (Curve crv in c)
        crvs.SetValue(crv.DuplicateCurve(), i++);
    }

    internal void MakeSrf(int ctn, double et, double it, double at){
      srf = NurbsSurface.CreateNetworkSurface(crvs, ctn, et, it, at, out ei);
    }
  }

// the standard runscript in a C# component of grasshopper
private void RunScript(DataTree<Curve> C, ref object A)
  {
    // some variables

    NWSrf[] nwsobjs = new NWSrf[C.BranchCount];
    NurbsSurface[] nurbs = new NurbsSurface[C.BranchCount];

    // make all the object for parallel
    for (int bi = 0; bi < C.BranchCount; bi++){
      nwsobjs.SetValue(new NWSrf(C.Branch(bi)), bi);
    }

    // compute in parallel
    Parallel.For(0, nwsobjs.Length, bi => {
      nwsobjs[bi].MakeSrf(2, 0.01, 0.01, 0.01);
      });

    // query the results of each objects
    for (int bi = 0; bi < nwsobjs.Length; bi++){
      nurbs.SetValue(nwsobjs[bi].srf, bi);
    }

    A = nurbs;
  }

Hello,

First, I think you shouldn’t refer to “newsobjs” in parallel actions

Parallel.For(0, nwsobjs.Length, bi => {
      nwsobjs/*This can be accessed by multiple actions at the same time*/[bi].MakeSrf(2, 0.01, 0.01, 0.01);
});

You may need to pass the object “nwsobjs [bi]” to action like with Task(..., nwsobjs [bi])
Another option is to use ThreadPool.QueueUserWorkItem and CountdownEvent

Apart from “nwsobjs”, I don’t see

jmv

You can also create a function to lock the current thread to guarantee synchronisation between multiple threads. That way only one thread is allowed to index your data. But this all depends if create network surface is a thread safe rhinocommon method.

I changed this

Parallel.For(0, nwsobjs.Length, bi => {
      nwsobjs[bi].MakeSrf(2, 0.01, 0.01, 0.01);
      });

to the following

object locker = new object();
Parallel.For(0, nwsobjs.BranchCount, bi => {
    NWSrf obj;
    lock (locker) obj = nwsobjs.Branch(bi)[0];
    obj.MakeSrf(2, 0.01, 0.01, 0.01);
    });

Is that what you mean? It still crashes. Does it tell us that the rhinocommon method is NOT thread safe?

I guess this error is not from your code.
Maybe the McNell team will have more ideas.
I did several tests, nothing worked correctly.

ah thanks for testing it out!
the indexing within Parallel.For() actually works on many rhinocommon calls such as sweeping or boolean differences, although it does look like a bad practice.
really makes me think this network srf api has something else…

Sorry, I really think this is from “CreateNetworkSurface” out of managed code.

Hi @Will_Wang,

Can you post a GH file I can load and run from here?

Thanks,

– Dale

here
don’t toggle to true or it blows up :stuck_out_tongue_winking_eye:

networksrf_parallel_crash_test.gh (21.0 KB)

is the method thread-unsafe? no easy way to multi-thread network srf is there?

Hi @Will_Wang,

Your solution seem to work in Rhino 7. What am I missing?

– Dale

Dale, You are not missing anything. I’m missing Rhino 7. You guys have a release date yet? Or any plans to fix these in Rhino 6?
Also the some multi thread crashes don’t take place regularly. It may or may not happen at each solution. Completely erratic. For example, I’ve found that Sweep2 multi-threaded crashes about 1 in 10 solutions.

Hi @Will_Wang,

No. But we’ve moved from the WIP phase to the Beta phase, which is good news.

At this point in the Rhino 6 development, probably not.

– Dale

I actually have BETA installed and it still crashes.
Did you try toggling in my script?

:thinking:

@Will_Wang - I did toggle the Boolean to True, and I moved the slider a bunch.

oh wow I’m lost
@kitjmv seems to experience this too
Dale tell us where to buy the computer you have…

Hi @Will_Wang,

With some diligence, I was able to repeat the crash. I’ve logged the issue.

https://mcneel.myjetbrains.com/youtrack/issue/RH-61184

I am guessing this is why Grasshopper’s NetSurf component is not task-capable.

Note, this will not be fixed in Rhino 6.

– Dale

1 Like