LitJSON / litjson

JSON library for the .Net framework
https://litjson.net/
Other
1.36k stars 403 forks source link

Thread-Safety Issue #120

Closed Potossas closed 4 years ago

Potossas commented 4 years ago

Hey. I think I have met Some Thread-Safety Issue in this case: I plug LitJson in an Unity Game, and try too Call JsonMapper.ToObject in multi-thread. Often, it runs good, but rarely(it can recurrent) meet this Exception. The json text is contained in the Exception message.

I read source code, Is that possible to Make most public-static method of JsonMapper become non-static, And I havea chance to call ToObject like this: new JsonMapper().ToObject(strJsonText); For each thread, a isolated JsonMapper Object instance parse different json text. and it's would not cause a lot of CPU payload

ArgumentException: Field id defined on type JsonConfig.Id_DbOdds is not a field on the target object which is of type . Parameter name: obj System.Reflection.MonoField.SetValue (System.Object obj, System.Object val, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Globalization.CultureInfo culture) System.Reflection.FieldInfo.SetValue (System.Object obj, System.Object value) LitJson.JsonMapper.ReadValue (System.Type inst_type, LitJson.JsonReader reader) LitJson.JsonMapper.ReadValue (System.Type inst_type, LitJson.JsonReader reader) LitJson.JsonMapper.ReadValue (System.Type inst_type, LitJson.JsonReader reader) LitJson.JsonMapper.ToObject (System.String json, System.Type ConvertType) JsonConfig.BaseConfig.toObject (LitJson.JsonData data, System.String& strCheckConfigErrorMessage) JsonConfig.BaseConfig.Parse (Gear.Misc.B1`1 jsonSrcBox, System.String& strCheckConfigErrorMessage) JsonConfig.ConfigControl.ParseTable (System.Object objP) Rethrow as Exception: table: CfgGodHood, jsonSrc: {"id":1,"name":"萌芽天赋","icon":"icon1","quality":1,"attribute_num":1,"godhood_attribute":[{"id":1,"odds":25},{"id":2,"odds":25},{"id":3,"odds":25},{"id":4,"odds":25}],"exp_by_silver":"3~10","crit_by_silver":[{"id":1,"odds":40},{"id":2,"odds":60}],"exp_by_help_point":"4~12","crit_by_help_point":[{"id":1,"odds":30},{"id":2,"odds":50},{"id":3,"odds":20}],"exp_by_gold":"24~53","crit_by_gold":[{"id":1,"odds":10},{"id":2,"odds":40},{"id":3,"odds":30},{"id":4,"odds":20}],"strength_initial":138,"strength_growth":7.62,"agility_initial":205,"agility_growth":11.4,"intelligence_initial":28,"intelligence_growth":1.5},{"id":2,"name":"下位天赋","icon":"icon1","quality":2,"attribute_num":1,"godhood_attribute":[{"id":1,"odds":25},{"id":2,"odds":25},{"id":3,"odds":25},{"id":4,"odds":25}],"exp_by_silver":"3~10","crit_by_silver":[{"id":1,"odds":40},{"id":2,"odds":60}],"exp_by_help_point":"4~12","crit_by_help_point":[{"id":1,"odds":30},{"id":2,"odds":50},{"id":3,"odds":20}],"exp_by_gold":"24~53","crit_by_gold":[{"id":1,"odds":10},{"id":2,"odds":40},{"id":3,"odds":30},{"id":4,"odds":20}],"strength_initial":178,"strength_growth":9.86,"agility_initial":230,"agility_growth":12.83,"intelligence_initial":30,"intelligence_growth":1.7},{"id":3,"name":"中位天赋","icon":"icon1","quality":3,"attribute_num":2,"godhood_attribute":[{"id":1,"odds":25},{"id":2,"odds":25},{"id":3,"odds":25},{"id":4,"odds":25}],"exp_by_silver":"3~10","crit_by_silver":[{"id":1,"odds":40},{"id":2,"odds":60}],"exp_by_help_point":"4~12","crit_by_help_point":[{"id":1,"odds":30},{"id":2,"odds":50},{"id":3,"odds":20}],"exp_by_gold":"24~53","crit_by_gold":[{"id":1,"odds":10},{"id":2,"odds":40},{"id":3,"odds":30},{"id":4,"odds":20}],"strength_initial":446,"strength_growth":24.75,"agility_initial":258,"agility_growth":14.25,"intelligence_initial":34,"intelligence_growth":1.88},{"id":4,"name":"上位天赋","icon":"icon1","quality":4,"attribute_num":2,"godhood_attribute":[{"id":1,"odds":12.5},{"id":2,"odds":12.5},{"id":3,"odds":12.5},{"id":4,"odds":12.5},{"id":6,"odds":12.5},{"id":7,"odds":12.5},{"id":8,"odds":12.5},{"id":9,"odds":12.5}],"exp_by_silver":"3~10","crit_by_silver":[{"id":1,"odds":40},{"id":2,"odds":60}],"exp_by_help_point":"4~12","crit_by_help_point":[{"id":1,"odds":30},{"id":2,"odds":50},{"id":3,"odds":20}],"exp_by_gold":"24~53","crit_by_gold":[{"id":1,"odds":10},{"id":2,"odds":40},{"id":3,"odds":30},{"id":4,"odds":20}],"strength_initial":491,"strength_growth":27.23,"agility_initial":283,"agility_growth":15.68,"intelligence_initial":37,"intelligence_growth":2.07},{"id":5,"name":"领袖天赋","icon":"icon1","quality":5,"attribute_num":3,"godhood_attribute":[{"id":1,"odds":12.5},{"id":2,"odds":12.5},{"id":3,"odds":12.5},{"id":4,"odds":12.5},{"id":6,"odds":12.5},{"id":7,"odds":12.5},{"id":8,"odds":12.5},{"id":9,"odds":12.5}],"exp_by_silver":"3~10","crit_by_silver":[{"id":1,"odds":40},{"id":2,"odds":60}],"exp_by_help_point":"4~12","crit_by_help_point":[{"id":1,"odds":30},{"id":2,"odds":50},{"id":3,"odds":20}],"exp_by_gold":"24~53","crit_by_gold":[{"id":1,"odds":10},{"id":2,"odds":40},{"id":3,"odds":30},{"id":4,"odds":20}],"strength_initial":986,"strength_growth":54.81,"agility_initial":309,"agility_growth":17.1,"intelligence_initial":42,"intelligence_growth":2.25},{"id":6,"name":"至高天赋","icon":"icon1","quality":6,"attribute_num":3,"godhood_attribute":[{"id":1,"odds":12.5},{"id":2,"odds":12.5},{"id":3,"odds":12.5},{"id":4,"odds":12.5},{"id":6,"odds":12.5},{"id":7,"odds":12.5},{"id":8,"odds":12.5},{"id":9,"odds":12.5}],"exp_by_silver":"3~10","crit_by_silver":[{"id":1,"odds":40},{"id":2,"odds":60}],"exp_by_help_point":"4~12","crit_by_help_point":[{"id":1,"odds":30},{"id":2,"odds":50},{"id":3,"odds":20}],"exp_by_gold":"24~53","crit_by_gold":[{"id":1,"odds":10},{"id":2,"odds":40},{"id":3,"odds":30},{"id":4,"odds":20}],"strength_initial":1170,"strength_growth":64.94,"agility_initial":334,"agility_growth":18.53,"intelligence_initial":45,"intelligence_growth":2.45} UnityEngine.Debug:LogException(Exception) JsonConfig.ConfigControl:ParseTable(Object)


and Id_DbOdds is: public class Id_DbOdds { public int id; public double odds; }

and CfgItem is:

    public class CfgItem
    {
        /// <summary>id</summary>
        public int id;
        /// <summary>神格名字</summary>
        public string name;
        /// <summary>神格图标 </summary>
        public string icon;
        /// <summary>神格品质</summary>
        public int quality;
        /// <summary>属性数量</summary>
        public double attribute_num;
        /// <summary>神格属性[属性类型、随机几率]</summary>
        public List<Id_DbOdds> godhood_attribute;
        /// <summary>银币培养[最小经验,最大经验]</summary>
        /// 
        public string exp_by_silver;
        /// <summary>暴击几率(相对几率),暴击倍率(百分比)</summary>
        public List<Id_DbOdds> crit_by_silver;

        /// <summary>元气培养[最小经验,最大经验]</summary>
        public string exp_by_help_point;
        /// <summary>暴击几率(相对几率),暴击倍率(百分比)</summary>
        public List<Id_DbOdds> crit_by_help_point;

        /// <summary>金币培养[最小经验,最大经验]</summary>
        public string exp_by_gold;
        /// <summary>暴击几率(相对几率),暴击倍率(百分比)</summary>
        public List<Id_DbOdds> crit_by_gold;

        /// <summary>神格1初始值 </summary>
        public int strength_initial;
        /// <summary>神格1成长值</summary>
        public double strength_growth;
        /// <summary>神格2初始值 </summary>
        public int agility_initial;
        /// <summary>神格2成长值</summary>
        public double agility_growth;
        /// <summary>神格3初始值 </summary>
        public int intelligence_initial;
        /// <summary>神格3成长值</summary>
        public double intelligence_growth;

    }
Potossas commented 4 years ago

Hi guys, I find some new clue, System.Reflection.MonoField is an implement of System.Reflection.FieldInfo,I guess System.Reflection.MonoField is not thread-safty, so I surround a try-catch block outof JsonMapper.ToObject, like this

Exception lastException = null; for(int i = 0; i < 5; i++){ try{ object ret = JsonMapper.ToObject(str, itemType); return ret; }catch(Exception e){ if( e is ArgumentException || e is KeyNotFoundException ){ lastException = e; Debug.LogException(new RepoHelper.LogOnlyException("MonoFiled.SetValue Thread-Safty Issue occured: " + e.GetType().Name + ": " + e.Message)); Thread.Sleep(200); }else{ throw e; } } } throw lastException;

I recieved Exception report of this issue, and a for() block and Thread.sleep() may suppress this issue. May it useful for you.