Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

System.Thread.Abort() not working

Discussion in 'Scripting' started by friuns3, Nov 9, 2009.

  1. friuns3

    friuns3

    Joined:
    Oct 30, 2009
    Posts:
    274
    Hello

    When i start background Thread i cannot Abort it why? Unity just freezes next time when i start scene again. How i can fix this?

    [edited]
    Code (csharp):
    1.  
    2. public class Main : MonoBehaviour
    3. {
    4.     Thread t;
    5.     void Start()
    6.     {
    7.         t = new Thread(ts);
    8.         t.Start();
    9.         Debug.Log("good");
    10.     }
    11.     void ts()
    12.     {
    13.  
    14.         TcpListener ts = new TcpListener(IPAddress.Any, 5300);
    15.         ts.Start();
    16.         Socket sct = ts.AcceptSocket();
    17.  
    18.     }
    19.     void OnApplicationQuit()
    20.     {
    21.         t.Abort();
    22.         Debug.Log(t.IsAlive); //true (must be false)
    23.     }
    24. }
    25.  
    26.  
     
  2. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,603
    Your thread code is horror for the computer I fear.
    If you have a permanent background thread, then having thread sleep in is a must have.
     
  3. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,206
    Code (csharp):
    1.  
    2. Thread t;
    3.     void Start()
    4.     {
    5.         Thread t = new Thread(startThread);
    6.         t.IsBackground = true;
    7.     }
    8.  
    9.  
    Issue here is that you are making a local Thread t, along with your global Thread t, so which do you think is running?

    The global or the local?
    And dreamora is right, in your While loop, add a sleep in there of a milisecond or so. If you don't the process will never yield instruction back to the parent thread.
     
  4. friuns3

    friuns3

    Joined:
    Oct 30, 2009
    Posts:
    274
    thanks for fast reply! =)

    ok, i fixed it, that was mistake sorry=)

    "while(true)" it is just example , there can be any code like sync sockets.

    Still i have this question. why Abort() method not working?

    Sorry for my bad english=)
     
  5. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,206
    Put a try/catch statement in there, check thread state, if thread state running then call thread abort, you can check to see if the thread IsAlive also, which really is an overload for thread state, if t.IsAlive == true, then the thread is starting and running normally, so you can call t.Abort, otherwise you got something else going on.

    It is very hard to help troubleshoot when we are seeing incomplete non functional code. Could be anything going on, an infinite loop, no sleep calls, the thread isn't running so t.Abort is throwing an exception error which isn't being handled, etc.

    EDIT(yea your code isn't even calling t.Start())

    Your abort doesn't work because your thread isn't running and abort is throwing an exception.
     
  6. friuns3

    friuns3

    Joined:
    Oct 30, 2009
    Posts:
    274
    Sorry again =) i got this bug yesterday so i tried to write it without opening unity.

    Ok. Now i tested and realized that with Thread.Sleep(100); it is working.
    But with sync Sockets its not
    my point actually is get working sync Sockets=)

    there is new tested code, that freezes unity

    Code (csharp):
    1. public class Main : MonoBehaviour
    2. {
    3.     Thread t;
    4.     void Start()
    5.     {
    6.         t = new Thread(ts);
    7.         t.IsBackground= true;
    8.         t.Start();
    9.         Debug.Log("good");
    10.     }
    11.     void ts()
    12.     {
    13.  
    14.         try
    15.         {
    16.             TcpListener ts = new TcpListener(IPAddress.Any, 5300);
    17.             ts.Start();
    18.             Socket sct = ts.AcceptSocket();
    19.         }
    20.         catch { }
    21.  
    22.     }
    23.     void OnApplicationQuit()
    24.     {
    25.         if (t != null)
    26.         {
    27.             t.Abort();
    28.             Debug.Log(t.IsAlive); //true (must be false)
    29.         }
    30.         else Debug.Log("t is null");
    31.        
    32.     }
    33. }
     
  7. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,206
    Am not at home yet, so please forgive any untested syntax on my part, so this is from the "hip" as it where. Absolutely no testing from me right now, am helping by programming straight in this discussion thread.

    Code (csharp):
    1.  
    2. public class Main : MonoBehaviour
    3. {
    4.     Thread t;
    5.     ThreadStart tDelegate;
    6.     TcpListener ts;
    7.     Socket sct;
    8.     void Start()
    9.     {  
    10.         tDelegate = new ThreadStart(ts);
    11.         t = new Thread(tDelegate);
    12.         t.Start();
    13.         Debug.Log("good");
    14.     }
    15.     void ts()
    16.     {
    17.         ts = new TcpListener(IPAddress.Any, 5300);
    18.         ts.Start();
    19.         sct = ts.AcceptSocket();
    20.         Debug.Log("Successful start at this point");
    21.         Thread.Sleep(100);
    22.     }
    23.     void OnApplicationQuit()
    24.     {
    25.         if (t.IsAlive)
    26.         {
    27.             t.Abort();
    28.             Debug.Log(t.IsAlive); //true (must be false)
    29.         }
    30.         else
    31.         {
    32.             Debug.Log("Dead duck on Thanksgiving table");
    33.         }
    34.     }
    35. }
    36.  
    FYI this isn't all you need to do to use the TcpListener Async if that is what you are trying to accomplish, let me know if that is what you are truely trying to do.
     
  8. friuns3

    friuns3

    Joined:
    Oct 30, 2009
    Posts:
    274
    Thanks zumwalt, but Thread.IsAlive still returns True :(

    I have own .net network engine that using synchronized sockets. it is hard to rewrite everything to async sockets=).


    Code (csharp):
    1. public class Main : MonoBehaviour
    2. {
    3.     Thread t;
    4.     ThreadStart tDelegate;
    5.     TcpListener ts1;
    6.     Socket sct;
    7.     void Start()
    8.     {
    9.        
    10.         tDelegate = new ThreadStart(ts);
    11.         t = new Thread(tDelegate);
    12.         t.Start();
    13.         Debug.Log("good");
    14.     }
    15.     void ts()
    16.     {
    17.         ts1 = new TcpListener(IPAddress.Any, 5300);
    18.         ts1.Start();
    19.         sct = ts1.AcceptSocket();
    20.         Debug.Log("Successful start at this point");
    21.     }
    22.     void OnApplicationQuit()
    23.     {
    24.  
    25.         if (t.IsAlive)
    26.         {
    27.             t.Abort();
    28.             Debug.Log(t.IsAlive); //true (must be false)
    29.         }
    30.         else
    31.         {
    32.             Debug.Log("Dead duck on Thanksgiving table");
    33.         }
    34.     }
    35. }
     
  9. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,206
    Am home, pulling out my tcp/ip net sockets code and Unity on Windows, going to look at this right now.

    Edit: see if this stuff helps, see attached project, it is a VS 2008 project, and I have included a Unity project with it, the Unity project should work fine on the Mac and the visual studio 2008 on a PC.

    EDIT:
    Updated, no bugs as far as I know, some left over delegates which will be used later so I left them in there anyway.
     

    Attached Files:

  10. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,206
    That project I just slapped together quickly in just a couple of hours so it is probably not bug free, just something to get you started, I need to eat dinner now and play some PS3. See this image for results while in Unity with that thing. It is a starting point at least I think. If this doesn't help, I am not sure how to help you. (like I said though, probably some locks I didn't fix in the server or possibly some conversions I am not checking in the client, but this is like 2 hours or less thrown together while taking care of kids, animals, house, etc, so more like 45 minutes of work)
     

    Attached Files:

  11. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,206
    I am cleaning up the code for this thing and also making a windows client to go with it, will post a cleaner build tonight.
     
  12. friuns3

    friuns3

    Joined:
    Oct 30, 2009
    Posts:
    274
    Thanks much zumwalt for this sample.
    Seems that async sockets works in unity.
    How you add .net dll references in Unity?

    I checked your code and found that you used here TcpListener.Stop()
    i tried use in Unity but i got crash


    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Net.Sockets;
    4. using System.Threading;
    5. using System.Net;
    6. using System.IO;
    7. using System;
    8.  
    9. public class Main : MonoBehaviour
    10. {
    11.     Thread t;
    12.     ThreadStart tDelegate;
    13.     TcpListener ts1;
    14.     Socket sct;
    15.     void Start()
    16.     {
    17.        
    18.         tDelegate = new ThreadStart(tstart);
    19.         t = new Thread(tDelegate);
    20.         t.Start();        
    21.     }
    22.     void tstart()
    23.     {
    24.         ts1 = new TcpListener(IPAddress.Any, 5300);
    25.         ts1.Start();
    26.         sct = ts1.AcceptSocket();        
    27.     }
    28.     void OnApplicationQuit()
    29.     {
    30.         ts1.Stop(); //crash
    31.     }
    32. }
     
  13. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,206
    Well, if you have a .Net dll that is compiled with 2.0 framework in mind, simply drag and drop the DLL into the root of the assets folder, then add a Using statement at the top like you would normally in C#. At that point you can use the DLL.

    If you take a look at the LinkSyncSRC.cs file, you will see that at the top I have the following:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Runtime.InteropServices;
    5. using UnityTCPIPLib;
    6. using System.Security.Permissions;
    7. using System.Threading;
    8.  
    The permissions one isn't used in this example so you can forget that one if you want.

    Now on into the core code:
    Code (csharp):
    1.  
    2.    Connector test; // member of the UnityTCPIPLib
    3.    string lastMessage; // what we have received last
    4.    public Transform PlayerCoord; // transform position of target object
    5.  
    6.    void Start()
    7.    {
    8.      test = new Connector(); // our guts and glory
    9.      Debug.Log(test.fnConnectResult("localhost", 10000, "Test User"));
    10.      // localhost obvious, 10000 port, Test User player name
    11.      if (test.res != "")
    12.      {
    13.         Debug.Log(test.res);// how did we do
    14.      }
    15.    }
    16.  
    At this point, I have made a connection to the server, passed it some info, and received an ACK back so I know things are working. Sockets are not the most effecient way to do things but hey. So now after I do some key checking, passing test data back and forth from Unity, when you close Unity:

    Code (csharp):
    1.  
    2. void OnApplicationQuit()
    3. {
    4.    try { test.fnDisconnect(); }
    5.    catch {}
    6. }
    7.  
    Notice something here, I am ignoring any errors spit back at me. There is a purpose to this madness, you see, when you close the socket connection, or make a call to have it do this, you are not guaranteed that it happens immediately so the socket remains open and locked for a short period of time, but that time will exceed a game loop duration. And we really don't need to care.

    When we shut down the listener in Unity, you need to wrap it in a try/catch because the listener can delay on shutting down and Unity won't take that into consideration when the Editor tries to terminate the thread. The Editor is non-bias on this, it has no care about your threads at-all and no way for Unity to know or understand threads you create.

    So in essance, for a moment, we are orphaning the thread but the call to terminate it is queued up in windows message queu and will eventually trigger (rather short time, but enough to make Unity puke), change your code to:

    Code (csharp):
    1.  
    2.  void OnApplicationQuit()
    3.     {
    4.        try
    5.        {
    6.         ts1.Stop();
    7.        }
    8.        catch(Exception e)
    9.        {
    10.           Debug.Log(e.ToString());
    11.        }
    12.     }
    13.  

    Then look at the log, most likely you will have a error related to a lock state call, which is safe to ignore. I have updated the code some today for VS 2008 client/server/DLL, and have been testing it locally. I will test it against Unity in the next few hours and add some more outputs in the editor and post up the new build / code and screenshots. Hopefully it will be pretty straight forward.

    I wouldn't recommend using this for anything over 4 players though and most certainly nothing with massive amounts of data back and forth, I have seen as much as 120ms delay between the player announce himself to the server, the server broadcast that player attaching to all connected and those connected refresh their player list with that new player.

    Although that could simply be my dev machine.
    Let me know if any of this information helps.
     
  14. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,206
    Ok, latest and final build has been posted to the threads [scroll up and get it from the same post as the previous build], this build does many things for you and you can use it as a building block shell. I have included a total of 3 project in the solution and I have included a Unity package also that uses it. Make sure that the Transform is attached to the main camera or some object, and make sure you give a value to the PlayerName in the inspector. Unity should -not- crash with this build. Also, I included not only the server, but a windows client that uses it, so you can start the server, then start Unity, then start the Windows Client and they will communicate.

    Frankly networking with Unity doesn't get much simpler than this shell. And this should work just as easily with Unity vs Unity Pro, should work without Pro. The Unity piece should also work on a Mac, so let me know if it doesn't, just interested to see how this works for people who are wanting to go down the *shivers* TCP/IP Sockets path.
    Here is a screen shot of what I am talking about:
     

    Attached Files:

  15. friuns3

    friuns3

    Joined:
    Oct 30, 2009
    Posts:
    274
    this not work, but i found why unity crashes.

    if you throw exception in non STAThread

    Code (csharp):
    1. public class Main : MonoBehaviour
    2. {
    3.     Thread t;
    4.     ThreadStart tDelegate;        
    5.     void Start()
    6.     {        
    7.         tDelegate = new ThreadStart(tstart);
    8.         t = new Thread(tDelegate);
    9.         t.Start();        
    10.     }    
    11.     void tstart()
    12.     {
    13.         throw new Exception(); //unity editor crash
    14.     }    
    15. }
     

    Attached Files:

  16. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,206
    Have you downloaded the ZIP a few posts up:
    UnityTCPIPNetwork.zip <- scroll up to grab it, somewhere around the middle of page 1 of this thread

    I have a script file in that zip for Unity that you should really take a look at, I am pretty confident that once you look through that script file you will see how to start your own threads in Unity and terminate them normally without Unity crapping out. You have to have things placed in the right areas and called in certain order or else you will blow up Unity.

    All your thread does here, is throw up an error "while" it is running, which terminates that thread abnormally and thus in the Editor, Unity has no clue what just happened because the exception was not handled at all. An unhandled thread error like this will always make Unity puke.
     
  17. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,206
    I spent a few minutes to make this even easier, see attached document on threading with Unity, probably a good education entry for UniKnowledge, who knows.

    This script you attach to ANY game object and make sure you set the player to run in background, then click on Windows, Console so you can see the console window and watch it!

    Hit play, watch, then hit play again to stop and see termination of thread, no crash and no errors.
     

    Attached Files:

  18. hierro

    hierro

    Joined:
    Dec 22, 2009
    Posts:
    27
    Hi, i',ve read all the post and used that code, of course when i'm trying to move the camera using values from socket, unity crahses, i'm not that much into this stuff, could somebody help me handling this threads ?
     
  19. alimolavi

    alimolavi

    Joined:
    Apr 19, 2010
    Posts:
    35
    Hi zumwalt i download ur server and client unity application and i run it...

    first look there is no error unity log printed Connection success and Listener Started , and unity server example print Listener Started but i cant send any message to unity or windows client application !

    please help me and pardon me for bad English writing ...
     
  20. ruckus37

    ruckus37

    Joined:
    May 11, 2010
    Posts:
    15
    zumwalt, great example, thanks, but i am also having problems with broadcasting messages to unity, the windows form and server boradcast just fine, but the unity app does not recieve the bradcast :( any help on this issue?
     
  21. ruckus37

    ruckus37

    Joined:
    May 11, 2010
    Posts:
    15
    Ok i see, nothing happening in the void Update(), what should go here?
     
  22. ruckus37

    ruckus37

    Joined:
    May 11, 2010
    Posts:
    15
    Fixed: just added Debug.Log (test.res); working great, thanks again, good learing point :)
     
  23. ruckus37

    ruckus37

    Joined:
    May 11, 2010
    Posts:
    15
    For anyone else using the unity example posted by zumwalt in this thread, just add the following to LinkSyncSCR.cs to get braodcast back to unity;

     
  24. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    3,852
    I know this is an old thread, but I thought it was worth pointing out that the the sample posted in $simplethreadmodel_587.cs is actually just a workaround for the fact that System.Threading.Abort() causes Unity to freeze as the OP originally stated. The freeze is caused by the thread never finishing. This is still the case. In the posted code, System.Abort() is never actually called. Instead it is working around the issue by using the shouldRun flag. You can verify this by simply running the first chunk of sample code on MSDN on this page in Unity. It will freeze Unity when the thread is aborted every time because its waiting for the thread to end but it doesn't. Inserting a flag to halt the while loop will make it work, however this is just a workaround for the bug.

    According to MSDN, Thread.Abort should raise an exception in the thread, which you can catch, that should stop the while loop. The exception is never raised when Thread.Abort is called in Unity.

    The following sample code illustrates the point. The thread will run and show the isAlive status in the console on every Update loop. Press the Zero key on the keyboard to try to abort the thread. You will see the abort was attempted, but the thread will continue to run forever returning isAlive = True no matter how many times you abort it.

    Code (csharp):
    1. using UnityEngine;
    2. using System.Threading;
    3.  
    4. public class ThreadingTest : MonoBehaviour {
    5.  
    6.   private Thread thread;
    7.  
    8.   void Awake() {
    9.     thread = new Thread(new ThreadStart(OnThreadStarted));
    10.     thread.Start();
    11.     while(!thread.IsAlive); // wait for thread to start
    12.     Debug.Log("Thread started : " + Time.realtimeSinceStartup);
    13.   }
    14.  
    15.   void Update() {
    16.     Debug.Log("Thread is alive = " + thread.IsAlive);
    17.  
    18.     if(Input.GetKeyDown(KeyCode.Alpha0)) {
    19.       EndThread();
    20.     }
    21.   }
    22.  
    23.   void OnDestroy() {
    24.     EndThread();
    25.   }
    26.  
    27.   void EndThread() {
    28.     try {
    29.       if(thread.IsAlive) {
    30.         thread.Abort();
    31.         Debug.Log("Trying to abort");
    32.       }
    33.     } catch {
    34.       Debug.Log("Aborting thread failed");
    35.     }
    36.   }
    37.  
    38.   void OnThreadStarted() {
    39.     try {
    40.       while(true) {
    41.         // loop until the thread is aborted
    42.       }
    43.     } catch(ThreadAbortException ex) {
    44.       // exception should be raised by Thread.Abort
    45.     }
    46.   }
    47. }
    48.  
     
    Last edited: Nov 6, 2014
  25. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    825
    On Windows, Mono uses APCs (Asynchronous Procedure Calls) for the thread abort logic. This means that when you call Thread.Abort(), an APC request is added to the given thread. However, user APCs are only run when the thread goes into what is called an "alertable" state. Simply put, this means that the thread has to call a Windows API that may block. Since this never happens in the code shown here (where the thread is made to spin), the exception won't be thrown.

    Also, the assumption that Thread.IsAlive must be false after calling Thread.Abort() is incorrect. Thread.Abort(), like basically every cross-thread operation, is an asynchronous operation. It is a request on the thread that, in order to have an effect, must be processed *on* that thread. This may happen soon or may happen much later -- depending on when the OS schedules the thread and depending on how fast the thread picks up the request.

    Finally, Thread.Abort() is the wrong tool for the job (well, in fact, there isn't a job for which Thread.Abort() is a good tool). Use either a semaphore or simply a global flag that tells the thread to exit. Trying to kill a thread with Thread.Abort() leads to all kinds of problems.
     
    xgiovio and AndyMartin458 like this.
  26. ZimM

    ZimM

    Joined:
    Dec 24, 2012
    Posts:
    945
    @Rene Damm
    That's all good, but why then ThreadAbortException is called reliably on .NET runtime, but not Mono? In my case, my thread a doing synchronouse sockets, and Socket.Receive is blocking the thread until the new data arrives (and that may actually never happen). There is absolutely no way to notify the thread that it should be closed:
    1) The thread will never read a flag that tells it needs to exit because it is stuck in Socket.Receive, waiting for new data.
    2) It'll never go into "alertable" state, for the same reason, as the thread is already inside a blocking operation.
    Basically, a thread that is inside a blocking operation is unkillable. Why is that? Thread.Abort() works wonderfully on .NET even when inside a blocking operation. Whatever the explanation is - that's not an expected behaviour.
    Sure, Thread.Abort() is not the best tool for most situations, but in my case I just want to abort the thread, I don't care about its state anymore
     
  27. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    825
    Because .NET implements it differently. It does not use APCs and thus does not rely on a blocking operation being triggered. Newer versions of Mono also implement thread abortion differently. Currently, both the old Mono as well as the new il2cpp runtime have the problem described above. For il2cpp, this will be solved sometime in the near (?) future. For Mono, it'll be solved when we upgrade to the latest version.

    Mono uses select() for screening sockets for activity. This does not cause a thread to go into alertable state. IL2CPP uses WSAPoll() which (with indefinite timeout) actually does.

    Regardless, neither behavior is correct in terms of Thread.Abort. It should not rely on alertable thread states on Windows.

    Yes. A workaround is to add a fake socket which is used only to interrupt the thread.

    Or simply set IsBackground to true on the thread and it will automatically be shut down when the application domain is destroyed.

    Yes, it isn't. Proper behavior is what .NET does.

    On a sidenote, using Thread.Abort is generally a bad idea and is indicative of bad multi-threading practices. If the only way to get a thread to terminate is to outright kill it, the communication with the thread is usually done badly. Killing it is the easiest way and on .NET is *reasonably* safe but the right thing is to properly communicate with the thread to tell it when to exit.
     
  28. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    825
    And sorry for the way too late reply. The thread slipped through the net.
     
  29. Jack_LaSota

    Jack_LaSota

    Joined:
    Mar 30, 2015
    Posts:
    3
    "For il2cpp, this will be solved sometime in the near (?) future. For Mono, it'll be solved when we upgrade to the latest version."

    Is there still a planned fix for this? I'm trying to put sandboxed end-user scripting in my game using Jurassic which can kill a thread running user Javascript if it hangs, and the developers' advice is to use Thread.Abort: https://jurassic.codeplex.com/discussions/454749 Since the code that needs to be aborted is not my own, changing it to incorporate checks for whether it should break is not an option.
     
  30. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    825
    Planned, yes. We will implement this properly for il2cpp and eventually we will also upgrade Mono to latest (with il2cpp starting to rapidly spread to the runtime platforms, this is starting to be within close reach). Unfortunately, that won't help you right here and now.

    Killing a thread with Thead.Abort can still be a tricky thing, though. There's no guarantee that you can go on without problems except the code running on the thread is properly built with abortion/exceptions in mind. Otherwise you may still end up with improper cleanups and things such as locks still being held by the aborted thread.

    How's the JavaScript execution implemented? In C# or in native?
     
  31. Jack_LaSota

    Jack_LaSota

    Joined:
    Mar 30, 2015
    Posts:
    3
    It compiles the Javascript to IL.

    Is there a recommended replacement Javascript (or Python) engine to use besides Jurassic? It seems like they're all incompatible with Unity's old Mono and/or rely on CAS for security, which Microsoft says you shouldn't do even with the latest .NET, and I hear is implemented without actually denying any permission in Mono. I tried PyPy, but their sandbox doesn't work on Windows (at least in the current version). IronPython seems to be reliant on CAS for security. The latest Jint gives a strange reflection exception from the Unity compiler when I put it in the project folder. There's apparently an old "Unity Jint" port, which I haven't looked into much. I can't remember why I gave up on Noesis's Javascript.NET. I remember I had problems loading the platform-specific DLLs they provided in Unity, but have a vague feeling there was something else. There's also V8.NET, and ClearScript. Someone says here: http://forum.unity3d.com/threads/clearscript-integration.209321/ that ClearScript requires a library Mono lacks. I haven't looked into V8.NET.
     
  32. pld

    pld

    Joined:
    Dec 12, 2014
    Posts:
    5
    Rene, does the player (or Mono) internally call Thread.Abort() on shutdown? I have a situation where on Windows (but not OSX) the player hangs on quit. My application spawns several subthreads that do socket I/O. The subthreads are marked IsBackground=true; I thought that this would protect me from anything trying to Join() them on shutdown.

    I think I'm running into the behavior you described because when my threads don't block in socket reads (which I assume is a select() internally), my app doesn't hang on exit. To dispatch the Thread.Abort APC, do I have to intentionally enter some alertable wait state, like with a Sleep(0)? I could modify my I/O loop to do that, although it would require enabling socket timeouts and handling them properly.
     
  33. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    825
    @Jack_LaSota
    Sorry, unfortunately don't really have anything useful for you.

    What little I can say, however, is that I'm revising my original stance on Thread.Abort. While its implications on the implementation are really hairy, sometimes it is simply the most straightforward and actually best way to get rid of a thread. And .NET makes it as reasonably safe as such an operation can get, I think.

    So yeah, I'd probably use Thread.Abort in your case, too. And I'd be equally stumped about it not working as expected.

    Yes. .NET dictates that every thread on which you set IsBackground=true is not waited on upon shutdown but terminated using Thread.Abort instead. Given Mono's implementation, that means that if a background thread does something that Mono can't interrupt, Mono will keep waiting and waiting for the thread to respond to the abort request.

    We ran into the same problem with our own internal socket polling thread in il2cpp. As we do not have full support for Thread.Abort yet, we had busy socket polls hang the application on shutdown.

    One solution (or more precisely, workaround) to your problem is to have a fake dummy socket to which you listen in addition to the "real" ones you are interested in. To terminate the waiting thread, you then send some dummy data on the dummy socket that makes the waiting thread wake up and seeing that it received some activity on the dummy socket, it realizes that is should end its business and disappear out the next exit.

    Yup, unfortunately. On il2cpp we do it differently and I *think* we are actually in alertable state while waiting but I wouldn't stake my life on it and it's not like that's helping you a lot either.

    BTW, to highlight the complication here and the reason why this is so difficult to support... Thread.Abort is built on the premise that *regardless of what the thread currently does*, you can interrupt it and make it throw an exception. However, the thread may currently well be in OS kernel code or in the C runtime library and trying to inject an exception there (by reprogramming the instruction pointer, for example) may lead to all sorts of bad behavior.

    Imagine you make the thread throw inside of malloc() which currently holds a lock on the entire C runtime memory subsystem. That thing isn't normally exception safe so you're almost guaranteed to end up aborting the thread with the memory subsystem still being locked and any future call to malloc() or free() will deadlock.

    It's not an impossible problem to solve but it requires some tricky code to really make this work robustly (mostly).
     
  34. Zocker1996

    Zocker1996

    Joined:
    Jan 12, 2015
    Posts:
    20
    I know this is an old discussion but I found a better solution for situations where your thread is blocking on a socket operation.
    My problem was that I had an UDPClient that was blocking the thread with its receive method. If you stop Unity just make sure you also close the client:

    Code (CSharp):
    1. UDPClient Client;
    2. void Start ()
    3.     {
    4. #if UNITY_EDITOR
    5.         UnityEditor.EditorApplication.playmodeStateChanged = delegate () {
    6.             if (!UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode &&
    7.                 UnityEditor.EditorApplication.isPlaying) {
    8.                 if(Client!=null){
    9.                     Client.Close();
    10.                 }
    11.                 Debug.Log (string.Format("[{0}] Exiting playmode.",GetType().Name));
    12.             }
    13.         };
    14. #endif
    15. }
    I guess this will work with TCPClients, too.