Used in Windows DLL, FreeLibrary() hangs host program on unloading DLL.
PolyVinalDistillate opened this issue · comments
In a DLL with a single function executing the following test code after being loaded with LoadLibrary()
:
void DLL_EXPORT IdentifierFunction(char** sBuf)
{
*sBuf = (char*)sPluginID; //Simply returns sPluginID
printf("\n\nHello from TensorFlow C library version %s\n", TF_Version());
auto a = cppflow::tensor({1.0, 2.0, 3.0});
auto b = cppflow::fill({3}, 1.0);
printf("Testing CPPFlow Tensor Addition Example\n");
auto c = a+b;
std::cout << c << std::endl;
printf("\n\n");
}
I find that a subsequent call in the host program to FreeLibrary()
hangs the execution.
If I append the following to the end of the above function:
TFE_DeleteContext(cppflow::context::get_context());
Then I can call FreeLibrary()
without issue. I'm totally new to all this, so sorry if I'm missing something - but I feel like there's a bug here, as I saw a similar issue was closed last year due to inactivity.
P.S. trying to delete the context in DllMain() DLL_PROCESS_DETACH does not work, and neither does storing the TFE_Context* in a global variable to delete it later in DLL_PROCESS_DETACH.
Addition of TFE_DeleteContext(cppflow::context::get_context());
does occasionally cause hard crash (which is arguably bertter than total hang!).
I've used a dirty hack for now that solves my problem with minimal resistance and maximum bad practise! Hopefully it will help with working out what the "correct" fix should look like.
- I've added a function to cppflow::context:
void destroyContext(){if(this->tfe_context!=nullptr){TFE_DeleteContext(this->tfe_context);}this->tfe_context=nullptr;};
- I've adjusted the destructor in cppflow::context:
inline context::~context() {
if(this->tfe_context!=nullptr)
TFE_DeleteContext(this->tfe_context);
}
- I've added a function to my dll file that my host program always calls before calling
FreeLibrary()
:
void DLL_EXPORT CleanupFunction()
{
cppflow::get_global_context().destroyContext();
}
- I've executed
cppflow::get_global_context();
in myDllMain() DLL_PROCESS_ATTACH
to ensure there's a context created as soon as the DLL file is loaded withLoadLibrary()
.
I'd like to implement the "correct" fix myself in keeping with the programming style used here, however I'm afraid a lot of the C++ code looks pretty alien to me. For example, no matter how much I read up on it, the line std::unique_ptr<TFE_Op, decltype(&TFE_DeleteOp)> op(TFE_NewOp(context::get_context(), "Fill", context::get_status()), &TFE_DeleteOp);
might as well be written in forth! Should I find the time, I may someday master these strange constructs. It's the Standard Template Libraries - they break my brain!