Free multi-threading framework in C#: Executors Framework

I’ve implemented a small framework for multi-threading applications in a very clear way. It’s called “Executors Framework” and is inspired by similar constructs that are available in the Java standard library.

http://www.unifycommunity.com/wiki/index.php?title=Executors_Framework

Comments and feedback very welcome! Especially if you spot bugs or potential threading unsafeties. When it appears solid enough, I will link to the page from the Scripts list.

I couldn’t find anything like this in the .NET libraries, which is why I implemented it. Feel free to mention if this already exists in .NET, and I will put on the fool hat.

<:)

Edit: I should mention that this is for advanced users only - do not attempt to introduce multi-threading in your regular Unity code. The primary uses for this framework is when you are doing heavy isolated computations, or are interfacing with external entities/libs that have blocking calls or long return times.

Cool stuff! I’m not very familiar with C#'s threading libraries, so I can’t tell you if there’s something similar in there. All I know is that I really like this way of working in Java, and am happy to see it usable withing Unity. :slight_smile:

This looks really cool, can’t wait to play around with it to see what it can do :smile:

Cheers

Does this make my application made in unity use multi-threading of my PC quad core processors.

thanks
rahu

No, it’s more complicated than that. If you don’t know how to use this, you probably don’t need it.

Would it be possible to add callbacks (delegates) instead of polling for isDone?

Future<int> myFuture2 = myExecutor.Submit(new MultiplyIntsTask(5, 12), MyCallback);

Where MyCallback would be called upon Future task completion.

C# is not Java and you can do it much simpler (ICallable → Delegate, Begin/EndInvoke etc.)

For most cases Future by Joe Duffy will suffice.

public class Future<T> : IDisposable
{

    // Fields
    private readonly Func<T> _func;
    private Exception _except;
    private T _value;
    private ManualResetEvent _mre;

    // Constructors
    public Future(Func<T> func)
    {
        _func = func;
        ThreadPool.QueueUserWorkItem(Worker);
    }

    // Properties
    public bool IsDone { get; private set; }

    public T Value
    {
        get
        {
            // If the future isn't completed, we wait.
            if (!IsDone)
            {
                _mre = new ManualResetEvent(false);
                Thread.MemoryBarrier();
                if (IsDone)
                {
                    _mre.Close();
                    _mre = null;
                }
                else
                {
                    _mre.WaitOne();
                }
            }

            // If an exception was thrown by the future, repropagate it.
            if (_except != null)
            {
                throw _except;
            }

            return _value;
        }
    }

    // Methods
    public void Dispose()
    {
        if (_mre != null)
        {
            _mre.Close();
            _mre = null;
        }
    }

    private void Worker(object obj)
    {
        try
        {
            _value = _func();
        }
        catch (Exception e)
        {
            // Capture the exception. It will be propagated when the consumer
            // rendezvous with the future.
            _except = e;
        }
        finally
        {
            IsDone = true;
            Thread.MemoryBarrier();
            if (_mre != null)
            {
                _mre.Set();
            }
        }
    }

}

.Net has a BackgroundWorker class for this sort of thing - it is part of the Windows Forms system though, not sure if it can be used in Unity.

Thanks for sharing, and welcome to the forums! I wasn’t entirely aware of the capabilities of Begin/EndInvoke.

However:

  1. There appears to be considerable performance hits for using delegates and begin/endinvoke. I think my approach avoids this.

http://shiman.wordpress.com/2008/09/10/c-net-delegates-asynchronous-invocation-begininvoke-method/

  1. Begin/EndInvoke does not let you specify the manner in which the task gets processed. For me it’s very nice to be able to change between threaded and non-threaded by just changing a single instantiation line.

Yes, but it sort of defeats the purpose of the whole framework… because the callback would be called from a foreign thread, which is the “can of worms” we’re trying to avoid.

can of worms is a nice word for it :wink:
Unity isn’t threadsafe, on a real multi threading system chances are pretty realistic that it will bomb …
you can already see errors happening due to parallel www request to the same domain actually as the data loading for the data in the WWW object is async in unity 2.6.x too

Thanks for sharing, and welcome to the forums!
Thank You!

  1. There appears to be considerable performance hits for using delegates and begin/endinvoke. I think my approach avoids this.

Note that Joe’s code does not use Begin/EndInvoke, but uses very fast MemoryBarrier and ManualResetEvent for signaling.

I just got a nice idea for this - by introducing a Unity component class called ExecutionManager, we can do the polling in there and support the callback pattern that you requested. Will update the code soon.

And that was the last we ever saw of DavidB. He starved to death trying to solve the Dining Philosopher’s problem.

Big update, with more extensive unit tests, shutdown and cancel features, a Unity helper component for delegate callback support, and more.

http://www.unifycommunity.com/wiki/index.php?title=Executors_Framework

Actually… that code won’t work in Unity (even 3.0) I think, because it uses .NET 3.5 classes. And I did try good old delegates, but ran into synchronization problems. It appears to not be thread-safe to use surrounding-scope variables in a delegate called by another thread:

    for(int i = 1; i < 10; i++) {
      futures.Add(executor.Submit<double>(delegate () { return i*i; } ));
      expectedAnswers.Add(i * i);
    }

Or could this be just a Unity/Mono bug in this regard? I kind of expected ints like these to be copied into some kind of anonymous invisible object for the delegate to refer to, which should be thread safe.

^ Article is from 2006, I doubt it uses .Net 3.5 classes :wink:

Oh… my bad.. :slight_smile:
For some reason I thought it was using this:

Must have just been tired when I read it.

Edit: Found out what the problem was with anonymous delegates and accessing outer scope:

Thanks a lot for this! Was nice to use and set up, and helped me with throwing some md5-hash calculations on a thread, instead of stalling the app.

Big thanks :slight_smile: