non-threadsafe function called on non-main thread

75 views
Skip to first unread message

bpie...@gmail.com

unread,
May 18, 2021, 12:38:46 PM5/18/21
to Excel-DNA
I cannot recreate it readily, but on 2 occasions I have had a function called by a non-main thread (managed thread ID != 1) even though the function attribute explicitly contains IsThreadSafe = false (only other attributes are IsExceptionSafe = true and also name/description/category/help topic).

This occurred in an x64 Excel version 2104 (Build 13929.20372 Click-to-Run) running on Windows 10. I am using ExcelDna v1.1.1 and I register the functions by setting ExplicitRegistration="true" in the config and calling ExcelRegistration.GetExcelFunctions().RegisterFunctions().

When this happened, the function continued to be called on the non-main thread even after deleting and re-entering it. After closing and re-opening Excel, the function was properly called on the main UI thread. This happened once while debugging in Visual Studio and once when running Excel with the release version of the add-in.

This appears to be a pretty rare occurrence, and I now do a check of the managed thread ID in every function to ensure it returns 1 before assuming Excel is calling on the UI thread. But wondering if there could be some race condition in the function registration that allows this to happen.

Brian



Govert van Drimmelen

unread,
May 20, 2021, 2:39:59 PM5/20/21
to Excel-DNA
--------------------------------------------------
Excel-DNA is now registered on GitHub Sponsors.
Easily add Excel-DNA support to your private or corporate GitHub account.
--------------------------------------------------

Hi Brian,

This sounds like quite a serious bug in the add-in, Excel-DNA or Excel itself
I have not heard of anything like this before.

My first suggestion would be to confirm the registration strings that your functions are registered with, to make sure they are not being registered as ThreadSafe for some reason.
(Or does your add-in have some other IsThreadSafe=true functions?)

For this you can add an app.config file to the project and enable verbose logging to a file.
The config file might contain this:

<configuration>
  <system.diagnostics>
    <trace autoflush="false" indentsize="4"/>
    <sources>
      <source name="ExcelDna.Integration" switchValue="All">
        <listeners>
          <remove name="Default"/>
          <add name="LogDisplay" type="ExcelDna.Logging.LogDisplayTraceListener,ExcelDna.Integration">
            <filter type="System.Diagnostics.EventTypeFilter" initializeData="Off"/>
          </add>
          <add name="File" 
               type="System.Diagnostics.TextWriterTraceListener" 
               initializeData="ExcelDnaAddIn.log" />
        </listeners>
      </source>
    </sources>
  </system.diagnostics>
</configuration>

Then run your add-in and check for a new ExcelDnaAddIn.log file.
The log file will have some entries like this, with the FunctionType the part we're interested in:

ExcelDna.Integration Information: 3 : Register - XllPath=C:\Temp\CsDnaLogging\bin\Debug\CsDnaLogging-AddIn64.xll, ProcName=f0, FunctionType=QC%, Name=Test - Result=568131587

For ThreadSafe functions, the FunctionType will have a suffix $ like this

ExcelDna.Integration Information: 3 : Register - XllPath=C:\Temp\CsDnaLogging\bin\Debug\CsDnaLogging-AddIn64.xll, ProcName=f0, FunctionType=QC%$, Name=Test - Result=568131587

So you can check for anything suspicious around the registration from the log.

Another consideration is how your function is being called. If the function is considered async and being transformed by the ExcelDna Registration extension, then your the function would be called from another thread, even though the wrapper function with the Registration extension creates will be called on the main thread. It doesn't sound like you're in this situation , but it's worth confirming.

The Excel-DNA registration always runs on the main thread, so it's not clear that a race condition at the actual registration time.
However, depending on how your functions are processed before the Registration call, one might image an ExcelFunctionAttribute object might end up in the wrong place.

Beyond this, it might be a bug in Excel. Then might be quite hard to report without something to reproduce, but you might at least press the "Send a frown" button. If they changed anything related recently, maybe that rings an alarm bell.

In any event, please report back if you find out anything more.

-Govert

Message has been deleted
Message has been deleted

bpie...@gmail.com

unread,
May 21, 2021, 8:33:37 AM5/21/21
to Excel-DNA
Hi Govert,

I searched my code and can confirm that all functions are either explicitly marked with IsThreadSafe = false or have no marking at all related to thread safety. I had removed all of the thread safe functions in response to that weird issue I reported a while back that turned out to be an Excel issue (https://groups.google.com/g/exceldna/c/POnAhnG_3dw/m/todW5TUeBwAJ). I did the logging you recommended and can confirm that no methods are marked as thread safe. Total unique values of FunctionType are pasted below.

The method calls are all pretty straightforward, and the logging that captured the non-UI thread is done only when methods are called directly from Excel. None of the methods is marked as async or ever called elsewhere in the code by non-UI threads.

I do suspect an Excel issue, as Excel seems to be pretty fluid these days and I'm in their program to get releases early. Also no user has ever reported this issue. In any event, I now check for this and handle+log it so not critical unless it becomes something persistent and experienced by users. I'll send a frown to Excel so there is at least the chance somebody will take a look.

Brian

Here are those function types:

 FunctionType=Q
 FunctionType=Q#
 FunctionType=QQ
 FunctionType=QQ#
 FunctionType=QQQ
 FunctionType=QQQ#
 FunctionType=QQQQ
 FunctionType=QQQQ#
 FunctionType=QQQQQ
 FunctionType=QQQQQ#
 FunctionType=QQQQQQ
 FunctionType=QQQQQQ#
 FunctionType=QQQQQQQ
 FunctionType=QQQQQQQ#
 FunctionType=QQQQQQQQ
 FunctionType=QQQQQQQQQ
 FunctionType=QQQQQQQQQ#
 FunctionType=QQQQQQQQQQ
 FunctionType=QQQQQQQQQQ#
 FunctionType=QQQQQQQQQQQQQQQQQ#
 FunctionType=QQQQQQQQU#
 FunctionType=QQQQU
 FunctionType=QQQUQ#
 FunctionType=QQQUQQQ
 FunctionType=QQQUQQQQ#
 FunctionType=QQQUQQQQQQQ
 FunctionType=QQQUQUQQQ
 FunctionType=QQUQ
 FunctionType=QQUQQ
 FunctionType=QQUQQQQQ
 FunctionType=QQUQQQQQ#
 FunctionType=QQUQQQQQQU
 FunctionType=QQUUQQ
 FunctionType=QQUUQQQ
 FunctionType=QQUUUUUUUUUUUUUUUUUUUU
 FunctionType=QQUUUUUUUUUUUUUUUUUUUU#
 FunctionType=QUQ
 FunctionType=QUQQ
 FunctionType=QUQQQ
 FunctionType=QUQQQ#
 FunctionType=QUQQQQ
 FunctionType=QUQQQQQ
 FunctionType=QUQQQQQQ
 FunctionType=QUQQQUUQQ
 FunctionType=QUU
 FunctionType=QUUQQ#
 FunctionType=QUUQQQQQQ
 FunctionType=QUUQQQQQQQ
 FunctionType=QUUQQUUU
 FunctionType=QUUU
 FunctionType=QUUUQQ
 FunctionType=QUUUQQQQ
 FunctionType=QUUUU
 FunctionType=QUUUUQQQQ
 FunctionType=QUUUUU
 FunctionType=QUUUUUUQ
 FunctionType=QUUUUUUUUUU
 FunctionType=QUUUUUUUUUUUUUUUUUUUU
Reply all
Reply to author
Forward
0 new messages