Search Unity

Unity Threading Helper

Discussion in 'Assets and Asset Store' started by Marrrk, May 21, 2011.

  1. winterkewl

    winterkewl

    Joined:
    Oct 28, 2011
    Posts:
    53
    Hi Marrrk, Is there an analogous to the "Thread.IsBackground" when using Threading Helper like this:

    Code (csharp):
    1. MyThread = UnityThreadHelper.CreateThread(DoWork, true);
    The docs for threads say this will ensure a thread started will die correctly when the application quits, which seems like it's not happening right now in my current implementation. i.e. when I call

    Code (csharp):
    1. Application.LoadLevel(2);
    the code running in my

    Code (csharp):
    1. void DoWork(UnityThreading.ActionThread thread)
    2.     {
    3.         while (true)
    4.         {
    5.             lock (_locker)
    6.             {
    7.                 // Interesting stuff happens here. . .
    8.             }
    9.         }
    10.     }
    sporadically will just not give in and the application will hang instead of switching levels. Would I need to do something else to break my while loop or is there a way to set the created thread to be IsBackground?
     
  2. Oriam

    Oriam

    Joined:
    Nov 11, 2012
    Posts:
    23
    Hello Marrrk!

    I just bought the asset, I really think it will come in handy in the near future, however, I was reading the forums to find an answer for a current situation. If I understand correctly, then the following 2 code samples have similar "performance" right? I was looking for a quick Resources.LoadAll solution, because as it is now each call to Resources.LoadAll has a huge impact on the framerate.

    If this is right, then I'll guess I will have to use Coroutines and the single Resources.Load, which I was trying to avoid.

    Code (csharp):
    1.  
    2.         // Main Thread
    3.         foreach(string i in ResourcePaths)
    4.         {
    5.             // Just to benchmark
    6.             CurrentResources = Resources.LoadAll(i, typeof(GameObject));
    7.         }
    8.         int len = CurrentResources.Length;
    9.         GameObject spawn = (GameObject)Instantiate(CurrentResources[Random.Range(0, len)]);
    10.         spawn.transform.position += Vector3.up * 6;
    11.  
    Code (csharp):
    1.  
    2.         // New Thread
    3.         UnityThreadHelper.CreateThread(() =>
    4.         {
    5.                 foreach(string i in ResourcePaths)
    6.                     CurrentResources = UnityThreading.ThreadSafe.Resources.LoadAll(i, typeof(GameObject));
    7.  
    8.                 int len = CurrentResources.Length;
    9.  
    10.                 UnityThreadHelper.Dispatcher.Dispatch(() =>
    11.                 {
    12.                     GameObject spawn = (GameObject)Instantiate(CurrentResources[Random.Range(0, len)]);
    13.                     spawn.transform.position += Vector3.up * 6;
    14.                 });
    15.         });*/
    16.  
     
  3. tree1891

    tree1891

    Joined:
    Apr 8, 2010
    Posts:
    6
    Does it work in mobile (iOS, android)?
     
  4. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    @AlexZ: Do you have example Code for this behaviour?

    @winterkewl: The UTH should abort or later terminate the thread after serveral seconds wait time, but you can work together with the UTH by periodically checking the abort status (inside your while loop or at the while condition), thread.ShouldAbort should be the right property for this. If you want to run the thread without the UTH, you could also manage the UTH stuff self without the usage of the UTH class self. (well this sounds strange)

    @Oriam: Resources.Load/LoadAll is a unity API method, those are not usable outside of the main thread, so you will always execute it on the mainthread and gain no performance boost through any threads. This said, your second code example which uses the UTH will not work, because you use the Resources.LoadAll method inside a different thread than the main thread.

    @tree1891: I heard that it will work there from some people already using it, some threadsafety objects will homever not work on iOS, but you are not entitled to use those. You can grab the package from the startpost of this thread to test it out.
     
  5. Oriam

    Oriam

    Joined:
    Nov 11, 2012
    Posts:
    23
    Thanks, then I understood correctly :( However, the second code sample does work ( I based that code on your example in the unity package). It compiles and runs without any problems, I even think it is a little faster than the first code sample, but it may be only in my mind.

    Anyway, thanks a lot for the package, it will come in handy for other things not related to the Unity API.

    P.S. For anyone messing with loading assets at runtime, coroutines with the simple Resources.Load seems to work really nice (in performance), but it is more work indeed.
     
  6. adam718

    adam718

    Joined:
    Mar 11, 2012
    Posts:
    58
    Hi!
    I tried to load many images from external (like "D:\image.jpg") to texture but it was heavy work.
    I used WWW.
    Loading one image took 100 ms (image size is 1024 * 700)

    Code (csharp):
    1.  
    2.     void LoadImage()
    3.     {
    4.             float time = Time.realtimeSinceStartup * 1000;
    5.             string imagePath = "file://" + "D:/image.jpg";
    6.  
    7.             WWW www = new WWW(imagePath);
    8.             loadImageUrl(www);
    9.  
    10.             _texBg = www.texture;
    11.             // Destroy(temp);
    12.             www.Dispose();
    13.             www = null;
    14.             time = Time.realtimeSinceStartup * 1000 - time;  //. [B]it results in 100 ms to load 1024 * 700[/B]
    15.     }
    16.  
    17.     IEnumerator loadImageUrl(WWW www)
    18.     {
    19.         yield return www;
    20.  
    21.         if (www.error != null)
    22.         {
    23.             Debug.LogError("WWW Error: " + www.error);
    24.         }
    25.     }
    26.  
    So I decided to use multithread and load image in background.
    When I use your plugin, can I load image without delay?

    Thank you,
    Adam.
     
  7. adam718

    adam718

    Joined:
    Mar 11, 2012
    Posts:
    58
    The following code fails with error.
    LoadImage can only be called from the main thread.
    Constructors and field initializers will be executed from the loading thread when loading a scene.
    Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.


    Code (csharp):
    1.  
    2.     void OnGUI()
    3.     {
    4.         if (GUI.Button(new Rect(10, 10, 100, 50), "Load"))
    5.         {
    6.             UnityThreadHelper.CreateThread((obj) =>
    7.             {
    8.                 Debug.Log("CreateThread started OK");
    9.                 DoThreadWork();
    10.             });
    11.         }
    12.     }
    13.  
    14.     void DoThreadWork()
    15.     {
    16.         LoadImage("D:/001.jpg");
    17.     }
    18.  
    19.     Texture2D LoadImage(string path)
    20.     {
    21.         System.IO.FileStream fs = new FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read);
    22.         byte[] thebytes = new byte[fs.Length];
    23.         int temper = (int)fs.Length;
    24.         fs.Read(thebytes, 0, temper);
    25.  
    26.         texture.LoadImage(thebytes); // This cann't be called in thread ?
    27.         return texture;
    28.     }
    29.  
    30.  
    Regards,
    Adam.
     
  8. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    Correct, you need to dispatch this call to the main thread:
    Code (csharp):
    1.  
    2. UnityThreadHelper.Dispatcher.Dispatch(() => {
    3.   texture.LoadImage(thebytes);
    4. });
     
  9. adam718

    adam718

    Joined:
    Mar 11, 2012
    Posts:
    58
    Then could you tell me with my problem above?
     
  10. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    The WWW class is a Unity class which already works with a background thread, you can yield the www class to gain the results after the download has been finished. Use the www class in your Coroutines (Loading happens in the background but the result may be yielded.)
     
  11. dd619

    dd619

    Joined:
    Jul 31, 2012
    Posts:
    4
    But i have one question.

    can we use AndroidJavaObject in thread?

    Actually i am doing like this,


    myThread = UnityThreadHelper.CreateThread(() =>
    {
    AndroidJavaObject user_Object=new AndroidJavaObject("com.sample.example");
    string response= user_Object.Call<string>("return_Response");

    });


    Actually i am trying to get server response using android plugins but its froze the application until android function returns response.

    And i want to do this in background thread so that main thread of unity don't get affected,so i tried using the code above but its crashing the application.
     
    Last edited: Dec 6, 2012
  12. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    Iam not sure how the AndroidJavaObject works, but it seems to be a class from Unity and almost everything from Unity should be handled inside the main thread. Couldnt you create a pull mechanism for your Android object?

    Something like this:

    Code (csharp):
    1.  
    2. int pendingCallHandle = user_Object.Call<int>("longWorkingActionWhichUsesJavaThreads");
    3. ...
    4. if (user_Object.Call<bool>("CheckCallFinished", pendingCallHandle  ))
    5. {
    6.   string response =user_Object.Call<string>("getResponseForCall", pendingCallHandle  );
    7.   DoSomething(response);
    8. }
    9.  
    longWorkingActionWhichUsesJavaThreads would queue your normally blocking action into a background thread which works in the AndroidJavaObject and returns an unique id to your queued task
    CheckCallFinished would check your uniyue id wether the task has been completed
    and getResponseForCall would return the result for the unique id
     
  13. dd619

    dd619

    Joined:
    Jul 31, 2012
    Posts:
    4
    Thank you for reply, i'll try this.
     
  14. GammaPsh

    GammaPsh

    Joined:
    Dec 11, 2012
    Posts:
    2
    Hey Marrrk

    I have some problems, first of all, my project doesn't compile anymore for ios. So my question is, what does work on what kind of platform, and does it allow stripping?
    Code (csharp):
    1. Cross compilation job UnityThreadHelper.ThreadSafe.dll failed.
    2. UnityEngine.UnityException: Failed AOT cross compiler: /Applications/Unity/Unity.app/Contents/BuildTargetTools/iPhonePlayer/mono-xcompiler --aot=full,asmonly,nodebug,ficall,static,outfile="UnityThreadHelper.ThreadSafe.dll.s" "UnityThreadHelper.ThreadSafe.dll"  current dir : /Users/patricschmid/Documents/Unity Projekte/Lantal_Configurator/Unity4/Temp/StagingArea/Data/Managed
    3.  result file exists: False
    The second thing, is there something like RunOnMainthread(()=>{});

    May I describe a little what i want, I have a function to search for a special texture, and if it isn't present load it from where so ever.
    Now I planed to use a callback function when this process is finished, and of corse I want to Invoke this callback on the Mainthread to avoid problems with Unityobjects.
    Code (csharp):
    1.  
    2. private List<TextureInfo> loadedTextures;
    3.  
    4. public void GetTexture(int textureId, Action<Texture2D> callback)
    5.         {
    6.             UnityThreadHelper.TaskDistributor.Dispatch(()=>{
    7.                 IEnumerable<Texture2D> searchedTex =    from tex in loadedTextures
    8.                                                 where tex.textureId == textureId
    9.                                                 select tex.texture;
    10.                
    11.                 if(searchedTex.Count() > 0){
    12.                     callback(searchedTex.ElementAt(0));
    13.                 }
    14.            
    15.                
    16.                 //Get textureInfo object for specified textureId
    17.                 TextureInfo tInfo = SomeAwsomeDataManager.GetTextureInfo(textureId);
    18.                
    19.                 //Load the Texture, not yet defined if local or www or what ever
    20.                 Texture2D myTex = SomeAwsomeDataLoader.LoadTexture(tInfo.texturePath) as Texture2D;
    21.  
    22.                 //Save new Texture in TextureInfo object
    23.                 tInfo.texture = myTex;
    24.                 //Write to loadedTexture list
    25.                 loadedTextures.Add(tInfo);
    26.                 //Invoke callback function with loaded texture
    27.                 callback(tInfo.texture);
    28.             });
    29.         }
    The last Problem would be that I would have to lock the loadedTextures List because it gets modified in a different Threads, and that could cause the raceconditions you mentioned earlier in this thread. Now I know that im running into a problem here, but not yet how to handle it, so maybe you can loose some words how to setup such a lock flag and use it. Or you know a good tutorial for thread dummies like me.

    Thank you for your work on this!
    Gamma
     
    Last edited: Dec 14, 2012
  15. bambamyi

    bambamyi

    Joined:
    Nov 26, 2008
    Posts:
    91
    Hello!

    I have read through the posts but it is still unclear whether this will work for Android / iOS. Can you confirm that this awesome plugin works on Android/iOS? I would buy it in heartbeat!

    Thanks!
     
  16. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    Hi there,

    I can not answer this completely, as no one stated to me directly whether it works or not, but for iOS I have heard something positive. You can test it at the start post of this thread, there is still the free version of it (should be equal to the asset store version except some shiny helper classes and samples).

    @Gamma:

    The UnityThreadHelper.ThreadSafe.dll does not work yet with iOS, I dont own any iOS devices so I am unable to check out why, but the full code of it is included in the Asset so you can have a look around if you want to.

    To your second question: You can lock access to any object by using the lock keyword:

    Either like this:
    Code (csharp):
    1.  
    2. object syncRoot = new object();
    3. ...
    4. lock (syncRoot)
    5. {
    6.   loadedTextures.Add(someTexture);
    7. }
    8.  
    Or like this:
    Code (csharp):
    1.  
    2. lock (loadedTextures)
    3.   loadedTextures.Add(someTexture);
    4.  
     
  17. DuxDucis

    DuxDucis

    Joined:
    Nov 23, 2012
    Posts:
    51
    Hey Marrrk, thanks a lot for this. I wanted to ask you, under what license do you release this as I wanted to ask your permission for something, I'm developing a Network framework which will probably go to the asset store if it ever gets to production quality, would I be allowed to do this? Thanks again for this amazing help.
     
  18. duke

    duke

    Joined:
    Jan 10, 2007
    Posts:
    763
    How do I get this to work in the editor (like what the ExecuteInEditor attribute allows)?
     
    Last edited: Dec 26, 2012
  19. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    @DuxDucis: Do what you want with it, but please report any bugs :)

    @duke: You must invoke a scene update to allow the static dispatcher to work, I think it works best by setting something dirty or initiating a repaint. HandleUtility.Repaint() will do this for you. Everything else should work without this.
     
  20. mindlube

    mindlube

    Joined:
    Oct 3, 2008
    Posts:
    993
    UnityThreadHelper crashes the webplayer. I really need this asset for a webplayer project! Can we get it working?

    To replicate this problem, make a webplayer build of Examples.unity scene.
    Click on Sort Example | Start Task Distributor Sort

    In the webplayer log, you see endless entries like this

    MethodAccessException: Attempt to access a private/protected method failed.
    at System.Security.SecurityManager.ThrowException (System.Exception ex) [0x00000] in <filename unknown>:0
    at UnityThreading.Dispatcher.ProcessTasks () [0x00000] in <filename unknown>:0
    at UnityThreadHelper.Update () [0x00000] in <filename unknown>:0

    eventually it will crash like this
    ...

    ========== OUTPUTING STACK TRACE ==================

    (0x039B7C7D) (mono-1-vc): (filename not available): mono_reflection_get_custom_attrs_data + 0x2690
    (0x039C42FC) (mono-1-vc): (filename not available): mono_image_verify_tables + 0x2523
    (0x0395CE11) (mono-1-vc): (filename not available): mono_class_init + 0x7a
    (0x0395E532) (mono-1-vc): (filename not available): mono_class_is_assignable_from + 0x28
    (0x039A31FF) (mono-1-vc): (filename not available): mono_object_isinst + 0x36
    (0x03A37693) (mono-1-vc): (filename not available): mono_set_defaults + 0x952f
    (0x03C60DCF) ((module-name not available)): (filename not available): (function-name not available) + 0x0
    (0x0798B0AC) (Mono JIT code): (filename not available): UnityThreading.Dispatcher:processTasks () + 0x1c (0798B090 0798B0D9) [03C14D20 - Unity Child Domain] + 0x0
    (0x0798AF8B) (Mono JIT code): (filename not available): UnityThreadHelper:Update () + 0x23 (0798AF68 0798B05B) [03C14D20 - Unity Child Domain] + 0x0
    (0x0795E219) (Mono JIT code): (filename not available): (wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr) + 0x41 (0795E1D8 0795E26D) [03C14D20 - Unity Child Domain] + 0x0
    (0x03A30424) (mono-1-vc): (filename not available): mono_set_defaults + 0x22c0
    (0x0399EDCB) (mono-1-vc): (filename not available): mono_runtime_invoke + 0x51
    (0x024D361E) (webplayer_win): (filename not available): ??$Transfer@VSafeBinaryRead@@@Behaviour@@QAEXAAVSafeBinaryRead@@@Z + 0x7b541
    (0x024D32B3) (webplayer_win): (filename not available): ??$Transfer@VSafeBinaryRead@@@Behaviour@@QAEXAAVSafeBinaryRead@@@Z + 0x7b1d6
    (0x024D33FC) (webplayer_win): (filename not available): ??$Transfer@VSafeBinaryRead@@@Behaviour@@QAEXAAVSafeBinaryRead@@@Z + 0x7b31f
    (0x024CB0EA) (webplayer_win): (filename not available): ??$Transfer@VSafeBinaryRead@@@Behaviour@@QAEXAAVSafeBinaryRead@@@Z + 0x7300d
    (0x024CB118) (webplayer_win): (filename not available): ??$Transfer@VSafeBinaryRead@@@Behaviour@@QAEXAAVSafeBinaryRead@@@Z + 0x7303b
    (0x024CB125) (webplayer_win): (filename not available): ??$Transfer@VSafeBinaryRead@@@Behaviour@@QAEXAAVSafeBinaryRead@@@Z + 0x73048
    (0x024AF59B) (webplayer_win): (filename not available): ??$Transfer@VSafeBinaryRead@@@Behaviour@@QAEXAAVSafeBinaryRead@@@Z + 0x574be
    (0x02511A7C) (webplayer_win): (filename not available): UnityGetError + 0x528
    (0x02511BCB) (webplayer_win): (filename not available): UnityWinWebLoop + 0x149
    (0x0154C786) (npUnity3D32): (filename not available): (function-name not available) + 0x0
    (0x01543349) (npUnity3D32): (filename not available): UT_Uninstall + 0x100c
    (0x0154321E) (npUnity3D32): (filename not available): UT_Uninstall + 0xee1
    (0x015472D8) (npUnity3D32): (filename not available): (function-name not available) + 0x0
    (0x7E418734) (USER32): (filename not available): GetDC + 0x6d
    (0x7E418816) (USER32): (filename not available): GetDC + 0x14f
    (0x7E4189CD) (USER32): (filename not available): GetWindowLongW + 0x127
    (0x7E418A10) (USER32): (filename not available): DispatchMessageW + 0xf
    (0x106836AE) (xul): (filename not available): mozilla::services::_external_GetXULOverlayProviderService + 0x1c246
    (0x10686834) (xul): (filename not available): mozilla::services::_external_GetXULOverlayProviderService + 0x1f3cc
    (0x102CF361) (xul): (filename not available): NS_LogTerm_P + 0x220
    (0x102BEB8A) (xul): (filename not available): XRE_SetupDllBlocklist + 0xcbb8
    (0x10A42FE9) (xul): (filename not available): XRE_InitChildProcess + 0x2d6
    (0x0040126A) (plugin-container): (filename not available): (function-name not available) + 0x0
    (0x004014A0) (plugin-container): (filename not available): (function-name not available) + 0x0
    (0x7C81776F) (kernel32): (filename not available): RegisterWaitForInputIdle + 0x49

    ========== END OF STACKTRACE ===========

    121227 12:57:09 Setting error display: 'The content was stopped because a fatal
    content error has been detected.', details: '', link: 0
    web: shutdown player
     
  21. mindlube

    mindlube

    Joined:
    Oct 3, 2008
    Posts:
    993
    Ah crud, I read elsewhere that the webplayer doesn't allow access to the UnityEngine namespace from other threads :( Bummer. It would be nice if Unity Threading Helper displayed a warning about this somewhere.

    edit:

    OK See this post from ArenMook (NGUI author).
    http://forum.unity3d.com/threads/76087-WebPlayer-Multi-threading
    Maybe this technique would be better for UnityThreadHelper.Dispatcher.Dispatch , instead of whatever it's currently doing that hangs/crashes the webplayer?

    edit2:
    I attached some .cs code which runs fine in the webplayer. It's just a simple test of the technique ArenMook described in that other topic. I spent a couple of hours looking at the UnityThreadHelper source code and trying to get it to work in the webplayer. I'm giving up on UnityThreadHelper in the webplayer unless someone else has suggestions.
     

    Attached Files:

    Last edited: Dec 28, 2012
  22. duke

    duke

    Joined:
    Jan 10, 2007
    Posts:
    763
    May I suggest partially mirroring the TPL implementation for tasks? That is, you already have Task and Task<TResult>, but add Start() and continuations with ContinueWith().
     
  23. apprenticegc

    apprenticegc

    Joined:
    Apr 21, 2012
    Posts:
    25
    When I try to build on iOS, I get following error:

    Cross compilation job UnityThreadHelper.ThreadSafe.dll failed.
    UnityEngine.UnityException: Failed AOT cross compiler: /Applications/Unity/Unity.app/Contents/BuildTargetTools/iPhonePlayer/mono-xcompiler --aot=full,asmonly,nodebug,static,outfile="UnityThreadHelper.ThreadSafe.dll.s" "UnityThreadHelper.ThreadSafe.dll"

    Anything I need to pay attention to? Please help. Thanks.
     
  24. BrokeSpace

    BrokeSpace

    Joined:
    Jul 10, 2012
    Posts:
    6
    I just found this and I love it, I purchased the Asset Store version and parallelized my framework in literally minutes (all I had to do really was change a few things to prevent race conditions).

    I normally write my parallel code using openMP and MPI unfortunately can't use these in Unity with C# :( Given that we don't have access to the .NET 4 Parallel stuff this is fantastic. Great work!

    Also, I too would be interested in getting this working in the web player :)
     
  25. JohanHoltby

    JohanHoltby

    Joined:
    Feb 10, 2013
    Posts:
    89
    Hi!
    This code is awesome but I have some strange errors.

    How come that the line _lightDirty = true; is executed before meshRenderer.enabled=true; I thought that task2.Wait(); should prevent it from happening. I have tested to set brake points on meshRenderer.enabled=true; and _lightDirty = true; , but _lightDirty = true; is executed first. You could argue this is a bug in the editor, but since I'm fetching data using task = UnityThreadHelper.Dispatcher.Dispatch in other parts of the code and get errors because the wait function don't wait and the fetch data is not set when used by later parts of the code.

    Code (csharp):
    1. //Reset the meshData
    2.         meshData = new MeshData(materialList.materialList.Count);
    3.         meshNoneCollideData = new MeshData(materialList.materialList.Count);
    4.        
    5.         //Optimize the mesh for render.
    6.         Task task2;
    7.         task2 = UnityThreadHelper.Dispatcher.Dispatch(() =>{
    8.             _filter.sharedMesh.Optimize();      //Do not improve for real??
    9.             meshRenderer.enabled=true;
    10.         });
    11.         task2.Wait();
    12.         //colors(lightning) need to be set
    13.         _lightDirty = true;
    I did start try to use the ThreadSafe solution but run in to problems.

    Code (csharp):
    1. public Mesh ToMeshThreadSafe(Mesh mesh) {
    2.         try{
    3.             if(vertices.Count == 0) {
    4.                 GameObject.Destroy(mesh);
    5.                 return null;
    6.             }
    7.             UnityThreading.ThreadSafe.Mesh meshT = (UnityThreading.ThreadSafe.Mesh)mesh;
    8.            
    9.             if(meshT == null) meshT = (UnityThreading.ThreadSafe.Mesh)(new Mesh());
    10.            
    11.             meshT.Clear();
    12.             ....
    This code is run in a thread and i get the following error:

    NullReferenceException: Object reference not set to an instance of an object
    UnityThreading.ThreadSafe.Mesh.<Clear>b__39 ()
    UnityThreading.Task.Do ()
    UnityThreading.TaskBase.DoInternal ()
    UnityThreading.Dispatcher.RunTask (UnityThreading.TaskBase task)
    UnityThreading.Dispatcher.ProcessSingleTask ()
    UnityThreading.Dispatcher.ProcessTasksInternal ()
    UnityThreading.Dispatcher.ProcessTasks ()
    UnityThreadHelper.Update ()


    Any help is much appreciated!
    Best regards
    /Johan
     
    Last edited: Feb 15, 2013
  26. SilentWarrior

    SilentWarrior

    Joined:
    Aug 3, 2010
    Posts:
    107
    Hello, I am trying to do the following:

    Code (csharp):
    1.  
    2. public class EverRunningClock : Timer
    3. {
    4.     public string name = "";
    5.     public EverRunningClock(string name, int seconds, Action action)
    6.     {
    7.         this.name = name;
    8.         this.Interval = seconds * 1000;
    9.         this.Elapsed += (s, a) =>
    10.         {
    11.             Debug.Log("Running action : " + this.name);
    12.             UnityThreadHelper.Dispatcher.Dispatch(action);
    13.         };
    14.         this.Enabled = true;
    15.  
    16.         Main.Instance.timers.Add(this);
    17.     }
    18. }
    19.  
    However, i keep getting : "FindObjectsOfType can only be called from the main thread.", if I use the dispatcher, if I comment it out, it gives me other errors related to calling stuff like get_time from another thread.

    Any idea what is going on? I thought the dispatcher was supposed to fix this problem.
     
    Last edited: Apr 5, 2013
  27. SilentWarrior

    SilentWarrior

    Joined:
    Aug 3, 2010
    Posts:
    107
    After looking carefully, I realised that what I was trying to do was stupid, UnityThreadhelper can only invoke from a context he knows about, thus, it should only be dispatched from threads created by itself.

    So, instead of using the timer from the library, made my own that implements UnityThreadHelper threads, and works like a charm :D

    Here is the timer in case its helpful for anyone else:

    Code (csharp):
    1.  
    2. public class EverRunningClock
    3. {
    4.     public string name = "";
    5.     public int Interval = 1000;
    6.     public Action action = null;
    7.     public bool Enabled = true;
    8.  
    9.     private UnityThreading.ActionThread thread;
    10.     public EverRunningClock(string name, int seconds, Action action)
    11.     {
    12.         setup(name, seconds, action);
    13.     }
    14.     public EverRunningClock(string name, float seconds, Action action)
    15.     {
    16.         setup(name, seconds, action);
    17.     }
    18.     public void setup(string name, float seconds, Action action)
    19.     {
    20.         this.name = name;
    21.         if(action == null || string.IsNullOrEmpty(name) || seconds<0.001f)
    22.         {
    23.             Debug.LogWarning("Failing creating timer for "+name);
    24.             return;
    25.         }
    26.         this.Interval = Mathf.RoundToInt(seconds * 1000);
    27.         this.action = action;
    28.         this.Enabled = true;
    29.         Main.Instance.timers.Add(this);
    30.         lastTimePass = DateTime.Now;
    31.         this.thread = UnityThreadHelper.CreateThread(() => run());
    32.         this.thread.Start();
    33.     }
    34.  
    35.     private DateTime lastTimePass;
    36.     bool timeHasPassed()
    37.     {
    38.         TimeSpan timediff = DateTime.Now.Subtract(lastTimePass);
    39.         var ms = timediff.TotalMilliseconds;
    40.         if(ms >= Interval)
    41.         {
    42.             return true;
    43.         }
    44.         return false;
    45.     }
    46.  
    47.     private double lastwait = 0;
    48.     void run()
    49.     {
    50.         while(thread != null  !thread.ShouldStop)
    51.         {
    52.             if (Enabled  timeHasPassed()  action != null)
    53.             {
    54.                 Debug.Log(string.Format("[{0}] Running action: [{1}] delay: [{2}] seconds lastWait: [{3}]", DateTime.Now,this.name, Interval/1000, lastwait));
    55.                 thread.DispatchAndWait(action);
    56.                 lastTimePass = DateTime.Now;
    57.             }else
    58.             {
    59.                 // wait
    60.                 TimeSpan timediff = DateTime.Now.Subtract(lastTimePass);
    61.                 var ms = Interval - timediff.TotalMilliseconds;
    62.                 lastwait = ms;
    63.                 if(ms <=0)
    64.                     Thread.Sleep(100);
    65.                 else
    66.                     Thread.Sleep((int)(ms));
    67.             }
    68.         }
    69.     }
    70.     public void Dispose()
    71.     {
    72.         thread.AbortWaitForSeconds(0.5f);
    73.         thread.Dispose();
    74.     }
    75. }
    76.  
     
  28. Adireddi

    Adireddi

    Joined:
    Apr 10, 2013
    Posts:
    1
    Very useful! Thanks!
     
  29. zsa

    zsa

    Joined:
    Jun 6, 2013
    Posts:
    3
    greetings;

    i recently purchased this to add multi-threading, but have a few questions that aren't quite clear in the docs or forum post or are clear but it doesn't seem to be acting the way described.

    #1 -
    • I understand TaskDistributor is supposed to create threads automatically, counting virtual cpus * 3. When I use the task distributor I get the following:
    • I see only 8 additional threads started when running task distributor, even where I have sent out 1200 tasks that might take 1 minute to complete all of them
    • The machine still runs at 25% as if there are not being any threads used at all, but instead, everything I send on the TaskDistributor is running on main
    • I was previously running these tasks on another thread, but singleton, now using TaskDistributor, the machine boggles down and I have a major performance hit on the main thread because of this, even though it appears I'm placing these processes on multiple threads according to documentation.
    • Maybe I'm missing something very super simple that I just don't get. I even tried to create an instance instead of using static class but can't get the task distributor to run with an instance.


    MeshBuilder meshData = new MeshBuilder();

    var myTask = UnityThreadHelper.TaskDistributor.Dispatch(() =>
    CalculateChunk(_chunk, meshData)
    );

    myTask.Wait();
    meshData = myTask.Result;
    ConvertMesh(meshData);


    The above code is attached to about 1500 objects who update every frame checking to see if this code should be run. Are all of these tasks being distributed evenly, even though 1500 different objects are creating their own tasks individually?

    What is the proper way to handle all of these different tasks coming from different object instances?
     
  30. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    Hi there,

    I see that you wait immediately for the Task to complete after you have created and distributed it.This means that the MainThread (or whatever Thread is used for waiting) will sleep until the task has been completed.

    I suggest that you do following:
    Code (csharp):
    1.  
    2. UnityThreadHelper.TaskDistributor.Dispatch(() =>
    3. {
    4.   var meshData = CalculateChunk(_chunk, meshData);
    5.   UnityThreadHelper.Dispatcher.Dispatch(() =>
    6.   {
    7.     ConvertMesh(meshData);
    8.   });
    9. });
    10.  
    This will let your task operate inside his thread and send a message to the mainthread after it has finished, when this message is handled, your chunk will be converted to a mesh.
     
  31. zsa

    zsa

    Joined:
    Jun 6, 2013
    Posts:
    3
    thank you. I thought I was doing something stupid, but I'm glad it was just that and nothing overly complicated. Just didn't read anywhere, the part that the wait command basically sleeps the thread.
     
  32. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    What was your expectation Wait would do?
     
  33. Damocles

    Damocles

    Joined:
    Jul 21, 2012
    Posts:
    46
    Hi Marrrk, this threading system is great and really appreciated, but I do have one small suggestion: Make the ThreadBase.Thread property public (or give access to it through a method). I spent quite some time looking through the API for a way to change a thread's priority, only to give up and change your code to give me direct access to the Thread object.
     
  34. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    You can inherit from ThreadBase or any other class which already inherits from Threadbase, then you can access the Thread thread member variable.
     
  35. Alesk

    Alesk

    Joined:
    Jul 15, 2010
    Posts:
    340
    Hi,

    I've got an editor (non blocking) error with this great threading helper in Unity 4.1.5f1.
    The message is : !IsPlayingOrAllowExecuteInEditMode ()

    Here is the code to reproduce the problem.
    Add it to any gameobject, run the game and stop it, then do some clicks in the editor interface on some checkboxes of the inspector, and you should see the error in the console :/

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class threadingerrormessage : MonoBehaviour {
    7.  
    8.     void Update () {
    9.         int count = SystemInfo.processorCount;
    10.         int i;
    11.        
    12.         List<UnityThreading.Task> taskList = new List<UnityThreading.Task>();
    13.        
    14.         for(i=0;i<count;i++){
    15.             var tmp = i;
    16.             taskList.Add(UnityThreadHelper.TaskDistributor.Dispatch(() => Test(tmp))); 
    17.         }
    18.        
    19.         for(i=0;i<count;i++){
    20.             taskList[i].Wait();
    21.             taskList[i].Dispose();
    22.         }
    23.  
    24.         taskList.Clear();
    25.        
    26.     }
    27.    
    28.     public void Test(int a){
    29.         Debug.Log (a);
    30.     }
    31. }
    32.  
    Any idea to solve this problem ? I know this error message is kind of mysterious and has already been discussed here : http://answers.unity3d.com/questions/388767/how-to-find-what-is-causing-isplayingorallowinedit.html

    But no solution has been found until now, it seems... :-?
     
    Last edited: Jun 19, 2013
  36. Alesk

    Alesk

    Joined:
    Jul 15, 2010
    Posts:
    340
    Problem fixed !

    I've just updated my version of the Threading Helper to the last available on the first post ^_^
     
  37. Acelondoner

    Acelondoner

    Joined:
    Jul 27, 2012
    Posts:
    101
    Would just like to say, this is great! I have just been testing the free version and it works really well. Got all 8 cores on my machine utilized and improved performance considerably! Going to pay for the full version right now. Cheers :)
     
  38. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    Always good to hear that it was useful :)
     
  39. Alesk

    Alesk

    Joined:
    Jul 15, 2010
    Posts:
    340
    Hi !

    This time I have a real bug :(
    I'm using the free threading helper in the zip file found on the first post of this topic.
    Using it is crashing the web player (tested on FF, Chrome on Windows7 and Chrome on MacOS 10)

    It's woking in the editor or in exe runtime, but freeze the webplayer as soon as a new task is created, here is my code to reproduce the bug :

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;  
    4.  
    5. public class ThreadingBug : MonoBehaviour {
    6.    
    7.     List<UnityThreading.Task> taskList = new List<UnityThreading.Task>();
    8.     private int _coresCount;
    9.     private List<SortGrp> _sortGroups = new List<SortGrp>();
    10.     private IDComp comp = new IDComp();
    11.     double debugTime;
    12.    
    13.     int delay = 100;
    14.    
    15.     void Start () {
    16.         _coresCount = SystemInfo.processorCount;
    17.         SortGrp newGroup;
    18.         SortID s;
    19.         int i,j;
    20.        
    21.         for(i = 0 ; i < _coresCount ; i++){
    22.              newGroup = new SortGrp();
    23.             for(j = 0 ; j < 1000 ; j++){
    24.                 s = new SortID();
    25.                 s.order = Random.Range(0f,100f);
    26.                 newGroup.items.Add(s);
    27.             }
    28.             _sortGroups.Add(newGroup);
    29.         }
    30.        
    31.     }
    32.  
    33.     void Update () {
    34.        
    35.         if(delay < 0){
    36.             debugTime = Time.realtimeSinceStartup;
    37.             taskList.Clear();
    38.             int i;
    39.             for(i=0;i<_coresCount;i++){
    40.                 // crash occurs here !
    41.                 taskList.Add(UnityThreadHelper.TaskDistributor.Dispatch(() => _sortGroups[i].items.Sort(comp) ));
    42.                
    43.                 // simpler example, same crash
    44.                 //taskList.Add(UnityThreadHelper.TaskDistributor.Dispatch( () => {return;} ) );
    45.             }
    46.            
    47.             for(i = 0; i < taskList.Count ; i ++){
    48.                 taskList[i].Wait();
    49.                 taskList[i].Dispose();
    50.             }
    51.             taskList.Clear();
    52.             debugTime = Time.realtimeSinceStartup - debugTime;
    53.         }else{
    54.             delay --;  
    55.         }
    56.     }
    57.    
    58.     void OnGUI() {
    59.         if(delay > 0){
    60.             GUILayout.Label("countdown = "+delay);
    61.         }else{
    62.             GUILayout.Label("time = "+(debugTime*1000).ToString("f2")+"ms  "+Time.realtimeSinceStartup);
    63.         }
    64.     }
    65. }
    66.  
    67. public class SortID{
    68.     public float order;
    69. }
    70.  
    71. public class SortGrp{
    72.     public List<SortID> items = new List<SortID>();
    73. }
    74.  
    75. public class IDComp : IComparer<SortID>
    76. {
    77.     public int Compare(SortID a, SortID b)
    78.     {
    79.         return (a.order > b.order)?-1:1;
    80.     }
    81. }
    I've made two tests here, one with a sort on some lists and another with nothing involved, both are crashing in webplayer (wait for the count down)
    I'm using Unity Version 4.1.5f1 (ed5ea3281df6) Thu, 06 Jun 2013 17:31:29 GMT

    You can test it directly here : http://www.alesk.fr/stock/threadingcrash/

    Wait for the countdown, then you must see changing numbers, if nothing moves, it means it's crashed :(

    Can you do something about this, or should I report it to the Unity Team ?
     
  40. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    I need to check this out when I find some time for it, thanks for the report :)
     
  41. Sieth

    Sieth

    Joined:
    Nov 18, 2012
    Posts:
    3
    Looks like I'm running into the same bug, awesome to hear you are on it!
     
  42. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    I fixed the bug thanks to Thinksquirrel, he mentioned the webplayer bug a long time ago but the fix of it must be slipped away from my mind.

    I updated the attached file in the start post and the asset store version (still pending the review process).
     
  43. Alesk

    Alesk

    Joined:
    Jul 15, 2010
    Posts:
    340
    Yay ! That's working for me, you're the best, thanks a lot :)
     
  44. Sieth

    Sieth

    Joined:
    Nov 18, 2012
    Posts:
    3
    Awesome news. .I'll try this out the first chance I get. If it works, I'll head over to the store and pick up the full version. Thanks for taking the time to fix it.
     
  45. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    No problem, the fix was indeed needed, it was my fault for not fixing it a long time ago. I hope everything works so far.
     
  46. Alesk

    Alesk

    Joined:
    Jul 15, 2010
    Posts:
    340
  47. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    The fix is now in the AssetStore.
     
  48. Play_Edu

    Play_Edu

    Joined:
    Jun 10, 2012
    Posts:
    722
    great work
     
  49. lilymontoute

    lilymontoute

    Joined:
    Feb 8, 2011
    Posts:
    1,181
    Ah yea, I remember that bug...took a little while to figure out, I was surprised the webplayer actually would build...
     
  50. Fher

    Fher

    Joined:
    Aug 13, 2013
    Posts:
    5
    Hi there!

    I have a little problem with my code, when I compare a class inherited from Monobehaviour with null I get the following error:

    As I understand (by reading all this post and other ones) this is caused because Unity is trying to use his own API to make the comparisson between null and a MonoBehaviour object. I thought that buying the Asset Store version I would be able to make this works but I still have the same error.

    Could somebody help me? I don't know how to proceed.

    Thanks a lot.

    Edit
    It seems that I fixed the problem changing the comparisons like myObject == null by UnityThreading.ThreadSafe.Object.Equals(myObject, null) but I don't know If that's the correct way... there is a more elegant way?

    By the way, I'm invoking my method through UnityThreadHelper.TaskDistributor.Dispatch
     
    Last edited: Aug 13, 2013