Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice

IL2CPP compiler does not correctly handle Interlocked.CompareExchange<System.Object>

Discussion in 'Unity 5 Pre-order Beta' started by seattlebluesky, Jan 21, 2015.

  1. seattlebluesky

    seattlebluesky

    Joined:
    Sep 2, 2014
    Posts:
    170
    Entered as bug 665476. Using 5.0.0 Beta20 on Mac OS X 10.10.1.

    Code being compiled for WebGL (or iOS using IL2CPP as the backend) ... obviously this is a reduced code sample vs. a real synchronized collection implementation ;) but the issue still holds.

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Threading;
    4. using UnityEngine;
    5.  
    6. public class MyCollection /* : ICollection */
    7. {
    8.     private System.Object _syncRoot = null;
    9.  
    10.     public System.Object SyncRoot
    11.     {
    12.         get
    13.         {
    14.             if (null == _syncRoot) /* double checked locking */
    15.                 Interlocked.CompareExchange<System.Object>(ref _syncRoot, new System.Object(), null);
    16.             return _syncRoot;
    17.         }
    18.     }
    19. }
    20.  
    Generates the following error in the case of WebGL. For iOS a similar missing function call to 'InterlockedCompareExchangeImpl' error is generated by Xcode.

     
  2. seattlebluesky

    seattlebluesky

    Joined:
    Sep 2, 2014
    Posts:
    170
    FWIW reproducible in Beta21 also.
     
  3. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Hmm... I know WebGL doesn't support multithreading so it's possible that it hasn't been implemented yet for iOS in IL2CPP... but try it like this instead and see if it works:

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Threading;
    4. using UnityEngine;
    5.  
    6. public class MyCollection /* : ICollection */
    7. {
    8. private System.Object _lockObj = new System.Object();
    9. private System.Object _syncRoot = null;
    10. public System.Object SyncRoot
    11. {
    12.     get
    13.     {
    14.         if(null == _syncRoot)
    15.         {
    16.               lock(_lockObj)
    17.               {
    18.                    //Double check
    19.                    if(null == _syncRoot)
    20.                    {
    21.                         _syncRoot = new System.Object();
    22.                     }
    23.                }
    24.         }
    25.    
    26.         return _syncRoot;
    27.     }
    28. }
    29.  
    The above essentially does the exact same thing, just not in quite as simple a manner. The reason for the two null checks is first of all, to make sure the thread sync lock is only ever obtained if necessary since it's a relatively expensive operation, and the second null check is to make sure if other threads enter the lock after waiting for one to complete, they don't recreate the _syncRoot object.
     
  4. seattlebluesky

    seattlebluesky

    Joined:
    Sep 2, 2014
    Posts:
    170
    Reasonable. I decided to change the collection to match the mono approach of returning self/this as the sync object.
    Code (CSharp):
    1. public System.Object SyncRoot
    2. {
    3.     get    {return this;}
    4. }
    5.