none
ThreadLocal<T> initializer runs multiple times on the same thread? RRS feed

  • Question

  • Background:

    during the development of a custom field type i get the https://social.msdn.microsoft.com/Forums/office/en-US/fb1cb936-3abb-48c2-8d19-49007688dc34/custom-field-type-properties?forum=sharepointdevelopmentlegacy  issue. So I used [ThreadStatic]. 

    Later, i think threadpool might be a issue for [ThreadStatic], https://social.msdn.microsoft.com/Forums/vstudio/en-US/3d464b27-ac8c-4800-9d23-d8ddadb41931/threadstatic-and-the-threadpool?forum=clr suggest using ThreadLocal with referencing official library document.

    What follows is my current code:

            //[ThreadStatic]
            //protected static string enabledClaimProviders;
            protected ThreadLocal<string> enabledClaimProviders = new ThreadLocal<string>(delegate(){
                DiagnosticsService.Local.WriteTrace(0, DiagnosticsService.Local.Areas[DiagnosticsService.LOG_AREA].Categories[DiagnosticsService.LOG_Category_SPClaimPicker], Microsoft.SharePoint.Administration.TraceSeverity.Verbose, string.Concat(FieldTitle, " enabledClaimProviders ThreadLocal initialized in Managed Thread Id:", Thread.CurrentThread.ManagedThreadId, ", thread name ", Thread.CurrentThread.Name, ", native thread id ", ReaderWriterLockHelper.GetCurrentWin32ThreadId().ToString()));
                return string.Empty;
            }
    
            );
            public string EnabledClaimProviders
            {
                get
                {
                    DiagnosticsService.Local.WriteTrace(0, DiagnosticsService.Local.Areas[DiagnosticsService.LOG_AREA].Categories[DiagnosticsService.LOG_Category_SPClaimPicker], Microsoft.SharePoint.Administration.TraceSeverity.Verbose, string.Concat(FieldTitle, " enabledClaimProviders ThreadLocal return value ", enabledClaimProviders.Value, " in Managed Thread Id:", Thread.CurrentThread.ManagedThreadId, ", thread name ", Thread.CurrentThread.Name, ", native thread id ", ReaderWriterLockHelper.GetCurrentWin32ThreadId().ToString()));
                    return enabledClaimProviders.Value;
                }
                set
                {
                    if (value != null)
                    {
                        string old = enabledClaimProviders.Value;
                        enabledClaimProviders.Value = value;
                        DiagnosticsService.Local.WriteTrace(0, DiagnosticsService.Local.Areas[DiagnosticsService.LOG_AREA].Categories[DiagnosticsService.LOG_Category_SPClaimPicker], Microsoft.SharePoint.Administration.TraceSeverity.Verbose, string.Concat(string.IsNullOrWhiteSpace(Title) ? FieldTitle : Title, " set ThreadStatic enabledClaimProviders to ", value, " in Managed Thread Id:", Thread.CurrentThread.ManagedThreadId, ", thread name ", Thread.CurrentThread.Name, ", native thread id ", ReaderWriterLockHelper.GetCurrentWin32ThreadId().ToString(), " the old value is ", old, "  ", new StackTrace().ToString()));
                    }
                }
            }

    The problem

    i get is that the initializer runs multple times, and even after i had set the value. So, i always get empty string.

    in the first screenshot for sharepoint uls log, i see that the value is initialized after the set. So, i added  "string old = enabledClaimProviders.Value;" into the set, hoping that can fix the problem. However, as shown in the second screenshot, initializer does run before set, but after the set, initializer runs again!

     



    This seems incredible to me, i even suspect that my .net framework file is not authentic, how can i proove that it is authentic?



    • Edited by GuYuming Thursday, March 22, 2018 10:15 AM
    Thursday, March 22, 2018 9:39 AM

Answers

  • Hi GuYuming,

    Thank you for posting here.

    For your question, what you do you want to do via the enabledClaimProviders variable?

    We always use ThreadLocal to provide storage of data with default value. The usage is similar to the usage of LocalDataStoreSlot. According to the code you provided, the default value of enabledClaimProviders is string.Empty.

    I do not know SharePoint well, hence I do not know how to display it on sharepoint. But in your code, what is the new value you used to set on the enabledClaimProviders variable? I do not find the value to want to output. If you do not set the different value, it will return the default value.

    Here is a simple example about ThreadLocal for your reference without the SharePoint.

    static ThreadLocal<int> local = new ThreadLocal<int>(() => 123); static void Main(string[] args) { Console.WriteLine(local.Value);

    ThreadPool.QueueUserWorkItem(_ => Console.WriteLine(local.Value = 234)); Console.ReadKey(); }


    Best Regards.

    Wendy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Sunday, March 25, 2018 2:37 PM
    Moderator

All replies

  • Hi GuYuming,

    Thank you for posting here.

    For your question, what you do you want to do via the enabledClaimProviders variable?

    We always use ThreadLocal to provide storage of data with default value. The usage is similar to the usage of LocalDataStoreSlot. According to the code you provided, the default value of enabledClaimProviders is string.Empty.

    I do not know SharePoint well, hence I do not know how to display it on sharepoint. But in your code, what is the new value you used to set on the enabledClaimProviders variable? I do not find the value to want to output. If you do not set the different value, it will return the default value.

    Here is a simple example about ThreadLocal for your reference without the SharePoint.

    static ThreadLocal<int> local = new ThreadLocal<int>(() => 123); static void Main(string[] args) { Console.WriteLine(local.Value);

    ThreadPool.QueueUserWorkItem(_ => Console.WriteLine(local.Value = 234)); Console.ReadKey(); }


    Best Regards.

    Wendy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Sunday, March 25, 2018 2:37 PM
    Moderator
  • thanks for replying.

    I figured it out now.

    i changed the definition to:

    protected static ThreadLocal<string> enabledClaimProviders

    ,now it works. ThreadLocal<T> should be declared as static here, the same as [ThreadStatic]. I just made a silly mistake.  The sample here (https://msdn.microsoft.com/en-us/library/dd642243(v=vs.110).aspx) is declared as instance, and can be misleading! 

    Monday, March 26, 2018 9:52 AM
  • and during test, i found that  Thread.GetData(Thread.GetNamedDataSlot("FieldName")) also does not clear value for theadpool, similar to [ThreadStatic].
    Monday, March 26, 2018 10:09 AM
  • Hi GuYuming,

    If your question has been solved, please mark the useful reply as answer. This will make answer searching easier in the forum and be beneficial to community members.

    Best Regards,

    Wendy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, March 30, 2018 7:02 AM
    Moderator