Search Unity

Android: Question about Threads and Static Variables

Discussion in 'Scripting' started by LandonC, Oct 16, 2019.

  1. LandonC

    LandonC

    Joined:
    Dec 20, 2012
    Posts:
    83
    I've been encountering a random error from an android plugin which runs on a separate thread. It's been happening randomly and for many times I thought I've solved it.

    Correct me if I'm wrong as I am not quite familiar with the terms but I'm pretty sure this is happening on a different one than Unity's since I have to use UnityDispatcher to make sure the run when the app pops back after the pop up window.

    Details:
    • This plugin is an ad plugin which would show an ad and returns back.
    • The callbacks provided by the mediator ran smoothly on debug, variables in it changed.
    • However when returned to the game, non of the variables changed in the callbacks were actually affected.

    So, I thought, maybe if the callbacks were changing static variables instead of public or private ones, would this make sure that the variables are ultimately changed??
     
  2. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    It would if only those variables aren't declared with ThreadStatic attribute on them.
     
  3. LandonC

    LandonC

    Joined:
    Dec 20, 2012
    Posts:
    83
    Very interesting. I never knew.

    I went to understand more of this ThreadStatic you mentioned.

    http://putridparrot.com/blog/using-threadstatic-and-threadlocal/
    https://stackoverflow.com/questions/57151054/viewing-threadstatic-variable-from-seperate-class

    Does it mean, that by default if I declare "public static int staticInt = 0;" on the Unity MainThread, it is not ThreadStatic? I'm kinda getting a better idea of why the plugin failed to change the variables.
     
  4. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    Yes, it does. By default variables are not ThreadStatic and changes to it are possible to and visible from any thread.
     
  5. LandonC

    LandonC

    Joined:
    Dec 20, 2012
    Posts:
    83
    It got me curious, what about Coroutines? Based on my understanding, coroutines happen in Unity's MainThread, they behave similarly like separate threads but they are not.

    What if I call a coroutine to wait for a variable that will be changed in another Thread, would that cause problems?
     
  6. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    That depends on your build and variable type. If your target .NET/mono and variable type is boolean or alike then it is safe because .NET standard guarantees word read/write to be atomic, but if your target is IL2CPP or type size is larger than one word (2 bytes for 32 bit and 4 bytes for 64 bit platforms) then no, it is not guaranteed to be atomic operation and you need some sort of syncronization mechanism like lock, mutex or lock-free collections.

    For instance, it might be so you have like Color variable and want to wait until it becomes black. There's an algorithm in main thread modifying it every frame and you put other thread in a loop like

    Code (CSharp):
    1. while(color != Color.black) Thread.Sleep(0);
    This code copies color variable from memory into local method stack and compares the copy against a constant. Reading the color variable is not guarateed to be atomic because color size is 4 x 4 = 16 bytes. Since it is not guaranteed, the OS scheduler may interrupt your thread at any moment. It is possible the scheduler will interrupt your thread after copying red and green components, but before blue and alpha. If schedulter will also run main thread after interrupting the one reading, then the main thread may change that variable and when the control flow will back to your thread it will finish reading. Its local copy will be corrupted - it will contain r and g from previous frame, and b and a from the current frame. Comparsion result will be invalid and program logic will be broken. Now look how many words like "may and possible" I've used here. Such bugs are almost impossible to reproduce and therefore to fix.
     
    LandonC likes this.
  7. LandonC

    LandonC

    Joined:
    Dec 20, 2012
    Posts:
    83
    OMG, that's it! I am using IL2CPP and changing an Enum. I have little to no idea what's IL2CPP for, only know that it is required on google play. Your explanation makes so much sense to my situation! I've move some functions to Update instead of the coroutine, hopefully, my problem will not happen anymore after this.

    Does it mean that Coroutines are not safe to use in many cases? It feels as if using too many of it causes undesired behavior.
     
    Last edited: Oct 16, 2019
  8. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    No, coroutines are run on the main thread and its absolutely safe to operate the same variables from normal mono behaviour callbacks and coroutines.
     
  9. LandonC

    LandonC

    Joined:
    Dec 20, 2012
    Posts:
    83
    I see, thanks for the enlightenment!