1

I'm working on a game in Unity and Unity is not threadsafe so whenever I do some calculations on different thread and want to go back to Unity I need to queue calls in some kind of queue so Unity can take those tasks and execute them on Unity thread. This is my code with tool that kind of gets job done:

public class Test : MonoBehaviour
{
    Thread someThread;

    private void Awake() //Executes on application start
    {
        someThread = new Thread(SomeThreadMethod);
        someThread.Start();
    }

    void SomeThreadMethod()
    {
        ExecuteInUpdate(MethodCalledNotInUnityThread);
    }

    // methods that I call from not unity thread but want to execute it IN unity thread
    void MethodCalledNotInUnityThread()
    {
        Debug.Log("Hello from UnityThread");
    }

    //--------------------------------------------------------------------------------
    //Tool for executing things in Unity Thread

    List<Action> actionQueues = new List<Action>();
    List<Action> actionCopiedQueue = new List<Action>();

    private volatile static bool noActionQueue = true;

    public void ExecuteInUpdate(Action _action)
    {
        lock (actionQueues)
        {
            actionQueues.Add(action);
            noActionQueue = false;
        }
    }

    public void Update()//runs all time, sort of while(true) loop in unity thread
    {
        if (noActionQueue)
        {
            return;
        }

        actionCopiedQueue.Clear();

        lock (actionQueues)
        {
            actionCopiedQueue.AddRange(actionQueues);
            actionQueues.Clear();
            noActionQueue = true;
        }

        for (int i = 0; i < actionCopiedQueue.Count; i++)
        {
            actionCopiedQueue[i]();
        }
    }
}

But the problem is it only works with methods that take no parameters. If I made a method like:

    void MethodCalledNotInUnityThread1(int _arg)
    {
        Debug.Log("Hello from UnityThread" + _arg);
    }

I could not call it cause it has parameter. I tried working with Action with generic parameter like

    Action<int> action

but then I can only pass methods that take only one parameter and it's int. I have many methods that take diffenet parameters in different amounts so how do I do it?

I want to achieve something like that:

    Dictionary<Action, object[]> paramsForAction = new Dictionary<Action, object[]>();

    public void ExecuteInUpdate(Action _action, params object[] _args)
    {
        paramsForAction.Add(action, args);//save params for action

        //add action to queue
    }

    public void Update()
    {
        //find action to execute

        object[] args = paramsForAction[actionToExecute];//get params for action
        actionToExecute(args);

    }

Of course it doesn't work and makes no sense but hopefully you can get what I'm trying to do.

Bizio
  • 45
  • 7
  • Not sure `lock` in `Update()` is a good idea. About your answer, you can define generic `Action` method, smth like `Action`, in this case, it will take parameters. – Alex Sikilinda May 20 '18 at 18:41
  • You should probably be using Task.Run instead of creating threads yourself. If you do it that way you can easily pass whatever arguments you want. – John Wu May 20 '18 at 19:46
  • That code is from [here](https://stackoverflow.com/questions/41330771/use-unity-api-from-another-thread-or-call-a-function-in-the-main-thread/41333540#41333540) and I provided examples on how to use it and you don't even need the `_args` parameter. This is what it looks like `UnityThread.executeInUpdate(()=> { //Call function with unlimited param here })`. This should execute your `Thread` in the main function. – Programmer May 20 '18 at 20:56

2 Answers2

2

Just wrap your method call in a lambda expression:

Action act = () => MethodCalledNotInUnityThread1(argVal1, argVal2); ExecuteInUpdate(act);

Pavel Tupitsyn
  • 8,393
  • 3
  • 22
  • 44
0

You could also just use Action<T>, where T is the first parameter of the method. Then there's also Action<T1, T2> for two parameters, etc.

And if you want a return type, Func<TResult> is the exact same idea, but with a return type of type. Func<TResult, TParam1>, etc.

AustinWBryan
  • 3,249
  • 3
  • 24
  • 42