Data race in MFC in afxCurrentResourceHandle - multithreading

we have an issue in MFC-based application related to “current MFC state” and threads. In main thread we call VisualManager, because we want to have fancy toolbars. The call ends up in CMFCVisualManagerOffice2007::OnUpdateSystemColors function located inside afxvisualmanageroffice2007.cpp, which changes “current resource handle” by calling AfxSetResourceHandle function. This function gets “current module state” and changes “current resource handle” from MyApp.exe to mfc140u.dll. This is fine, because assets for VisualManager are located in that DLL and the change will be restored back to MyApp.exe in all cases.
However, what is not fine is that we spawn a new thread just before call to VisualManager (by using AfxBeginThread), this thread needs to load some strings from string table (by using CString class), but it sometimes fails to do so. It fails because there is race with main thread about AFX_MODULE_STATE::m_hCurrentResourceHandle variable. The thread expect it to be set to MyApp.exe, but the main thread changes it to mfc140u.dll and back, the “current resource handle” is effectively a global variable.
So, my questions are: 1) Are we doing something obviously wrong managing our MFC-based threads? Should we somehow copy or protect the “module state” so our new thread is immune to the change main thread is doing? Should aim MFC to create something like per-thread variable / state? 2) I believe Microsoft is wrong here, changing what is effectively a global variable and screwing other threads expectations, VisualManager should obtain the handle and pass it to all its functions as a parameter. Am I right?
EDIT:
Hi guys #iinspectable, #cha, I have an update, sorry it took so long. Steps to reproduce: Open Visual Studio 2015 Update 3, Create new MFC application through the wizard, make sure it has the "Project style" and "Visual style and colors" selected as "Office" and "Office 2007 (Blue theme)". Open file afxvisualmanageroffice2007.cpp from MSVS folder and put 4 break-points into CMFCVisualManagerOffice2007::OnUpdateSystemColors function where it calls AfxSetResourceHandle. Open file MFCApplication1.cpp in your newly created project folder and put this code [1] into CMFCApplication4App::InitInstance function just before CMainFrame* pMainFrame = new CMainFrame;, put break-point into this thread proc.
Now build and run this MFC application in debug mode, on each break-point hit, use freeze thread and thaw thread functions from Threads window, so you will arrange main thread in the middle of CMFCVisualManagerOffice2007::OnUpdateSystemColors function just after setting the global variable using AfxSetResourceHandle function and the worker thread before CStringT::LoadString. Now the load string will fail because it is looking for it inside mfc140ud.dll instead of using resource chain and MFCApplication1.exe.
I believe this is Microsoft's bug (changing global variable for a while), my code-base is full of innocent CString::LoadString calls which rely on carefully and correctly constructed resource chain with various plug-in DLLs and with an .exe at the end. If this is not Microsoft's bug then it is my bug relying on MFC on providing me a usable resource chain. I would need to create my own resource-chain-like functionality and use it everywhere when loading strings and other stuff from resources.
// [1]
AFX_THREADPROC thread_proc = [](LPVOID pParam){
CString str;
str.LoadString(IDS_CAPTION_TEXT);
UINT ret = 0;
return ret;
};
::AfxBeginThread(thread_proc, (LPVOID)nullptr);
// Same result with ::AfxBeginThread(CRuntimeClass*) overload.

Related

Getting error "attempting to detach while still running code" when calling JavaVm->DetachCurrentThread [duplicate]

I have an Android app that uses NDK - a regular Android Java app with regular UI and C++ core. There are places in the core where I need to call Java methods, which means I need a JNIEnv* for that thread, which in turn means that I need to call JavaVM->AttachCurrentThread() to get the valid env.
Previously, was just doing AttachCurrentThread and didn't bother to detach at all. It worked fine in Dalvik, but ART aborts the application as soon as a thread that has called AttachCurrentThread exits without calling DetachCurrentThread. So I've read the JNI reference, and indeed it says that I must call DetachCurrentThread. But when I do that, ART aborts the app with the following message:
attempting to detach while still running code
What's the problem here, and how to call DetachCurrentThread properly?
Dalvik will also abort if the thread exits without detaching. This is implemented through a pthread key -- see threadExitCheck() in Thread.cpp.
A thread may not detach unless its call stack is empty. The reasoning behind this is to ensure that any resources like monitor locks (i.e. synchronized statements) are properly released as the stack unwinds.
The second and subsequent attach calls are, as defined by the spec, low-cost no-ops. There's no reference counting, so detach always detaches, no matter how many attaches have happened. One solution is to add your own reference-counted wrapper.
Another approach is to attach and detach every time. This is used by the app framework on certain callbacks. This wasn't so much a deliberate choice as a side-effect of wrapping Java sources around code developed primarily in C++, and trying to shoe-horn the functionality in. If you look at SurfaceTexture.cpp, particularly JNISurfaceTextureContext::onFrameAvailable(), you can see that when SurfaceTexture needs to invoke a Java-language callback function, it will attach the thread, invoke the callback, and then if the thread was just attached it will immediately detach it. The "needsDetach" flag is set by calling GetEnv to see if the thread was previously attached.
This isn't a great thing performance-wise, as each attach needs to allocate a Thread object and do some internal VM housekeeping, but it does yield the correct behavior.
I'll try a direct and practical approach (with sample code, without use of classes) answering this question for the occasional developer that came up with this error in android, in cases where they had it working and after a OS or framework update (Qt?) it started to give problems with that error and message.
JNIEXPORT void Java_com_package_class_function(JNIEnv* env.... {
JavaVM* jvm;
env->GetJavaVM(&jvm);
JNIEnv* myNewEnv; // as the code to run might be in a different thread (connections to signals for example) we will have a 'new one'
JavaVMAttachArgs jvmArgs;
jvmArgs.version = JNI_VERSION_1_6;
int attachedHere = 0; // know if detaching at the end is necessary
jint res = jvm->GetEnv((void**)&myNewEnv, JNI_VERSION_1_6); // checks if current env needs attaching or it is already attached
if (JNI_EDETACHED == res) {
// Supported but not attached yet, needs to call AttachCurrentThread
res = jvm->AttachCurrentThread(reinterpret_cast<JNIEnv **>(&myNewEnv), &jvmArgs);
if (JNI_OK == res) {
attachedHere = 1;
} else {
// Failed to attach, cancel
return;
}
} else if (JNI_OK == res) {
// Current thread already attached, do not attach 'again' (just to save the attachedHere flag)
// We make sure to keep attachedHere = 0
} else {
// JNI_EVERSION, specified version is not supported cancel this..
return;
}
// Execute code using myNewEnv
// ...
if (attachedHere) { // Key check
jvm->DetachCurrentThread(); // Done only when attachment was done here
}
}
Everything made sense after seeing the The Invocation API docs for GetEnv:
RETURNS:
If the current thread is not attached to the VM, sets *env to NULL, and returns JNI_EDETACHED. If the specified version is not supported, sets *env to NULL, and returns JNI_EVERSION. Otherwise, sets *env to the appropriate interface, and returns JNI_OK.
Credits to:
- This question Getting error "attempting to detach while still running code" when calling JavaVm->DetachCurrentThread that in its example made it clear that it was necessary to double check every time (even though before calling detach it doesn't do it).
- #Michael that in this question comments he notes it clearly about not calling detach.
- What #fadden said: "There's no reference counting, so detach always detaches, no matter how many attaches have happened."

Disposing of ExcelDnaUtil.Application from new thread

I'm using ExcelDNA to develop an XLL.
In it, I have a form living in a DLL to which I pass "ExcelDnaUtil.Application" as a member to facilitate interactions between the form and the instance of Excel running the XLL.
If I launch the form in the main thread using:
form1.show()
when I close the form then close Excel, Process Explorer shows that the Excel process is properly disposed of.
If I launch the form using a new thread:
Dim workerThread As Thread
workerThread = New Thread(Sub() form1.showdialog())
workerThread.Start()
when I close the form and then close Excel, the process remains in Process Explorer. I have been careful not to use two decimal points in any line of code and set the interface member to "nothing" when closing the form. I am not using "ReleaseCOMObject" as other articles have indicated that it is bad-practice.
Question: How do I dispose of the Excel process properly from a separate thread?
It's impossible to get the COM stuff right cross-thread.
You should never talk to the Excel COM object model from another thread. If you follow this one simple rule, you never have to worry about two dots, never have to set anything to Nothing and never have to call any of the ReleaseComObject hacks. And Excel will close nicely.
Since Excel is single-threaded (actually because the Excel COM object model lives in a Single-Threaded Apartment), there is no performance benefit from talking to Excel with another thread - internally it all gets marshalled to the main thread anyway.
If you dare to talk to Excel from another thread, then any COM call could fail, at any time. This is because Excel is still 'alive' and can go into a state where the 'object model is suspended', causing all COM calls to fail (with errors that even a COM message filter can't catch). When would Excel go into such a stubborn mode? When the user does something crazy like click their mouse button, for example.
How then to call back to Excel after you've done some work on another thread? Excel-DNA has a helper that will schedule work to be done back on the main thread, when Excel is in a mode where COM calls are safe. You just call ExcelAsyncUtil.QueueAsMacro(...) with a delegate containing the work to be done. This call can be made at any time from any thread, but the code will only run when ready.
A somewhat clumsy example is this:
Public Module MyFunctions
Dim workerThread As Thread
Public Function OverwriteMe() As Object
Dim caller = ExcelDnaUtil.Application.Caller
workerThread = New Thread( _
Sub()
Thread.Sleep(5000)
ExcelAsyncUtil.QueueAsMacro( _
Sub()
caller.Value = "Done!!!"
End Sub)
End Sub)
workerThread.Start()
Return "Doing it..."
End Function
End Module

Delphi: Exceptions when using adocomponents in objects that are created in a plugindll on threads

The situation:
I have an application and a plugin dll both written in delphi 7.
The dll exports 3 functions: createobject:pointer, runobject(instance:pointer), freeobject(instance:pointer).
createobject:pointer creates an instance of an dll-internal workobject and returns the pointer to the object.
runobject(instance:pointer) takes this instance pointer as a parameter and uses the pointer to start some processingfunction
in the objectinstance that this instance pointer points to.
freeobject(instance:pointer) takes the instance pointer and frees the internal object that this instance pointer points to.
I did this, so that i can create multiple workobject instances from the plugin dll.
Now, the application sets up 2 workerthreads. While setting up the 2 threads, the plugin dll is dynamically loaded twice via loadlibrary
(one for each thread) and the exported functions are given to the thread. (Note: because it's the same DLL with the same filename, the
DLL is loaded only once into my application and just the reference count of the loaded dll goes to 2.)
Each workerthread starts, calls CoInitialize(nil) to initialize the com system (because i want to use ado components) and then creates its
own dll-internal object via the dllfunction createobject and then calls runobject with the returned instancepointer as parameter.
Now, the code inside runobject uses adoconnection + adoquery components to read from a database.
The adocomponents are created inside the workobject and nothing is shared between the 2 threads... no global vars used.
The problem:
I get strange random accessviolations while the 2 objectinstances, each on its own thread, use their own ado components to read from the DB...!?
Both threads start to read some Databaserows. Then, at some random time and "random place" in the adoquery read code, exceptions are being raised.
"Random place" means, that the exceptions sometimes occur in the call to adoquery.open, sometimes in the call to adoquery.next...
the ado code is really simple... it looks like this:
with adoquery do
begin
sql.clear;
sql.add('select * from sometable');
open;
while not eof do
begin
test := fieldbyname('test').asstring;
next;
end;
close
end;
I did some testing:
a) If I use only 1 thread (and so only 1 workobject inside the dll is beeing created) then everything works fine.
b) If I make a copy of the DLL File with another filename but the same code inside this file, and thread_1 loads dll_1 and thread_2 loads dll_2
then these 2 identical dlls are really both beeing loaded into my application and everything works fine.(Note: loadlibrary in this test was called from the
context of the mainthread, not the context of each workerthread, but that seemed no problem because no exceptions did occur.)
c) If I don't use the DLL at all and just create my 2 workobjects directly on my 2 threads then everything works fine.
The exceptions only occur when I use adocomponents in 2 separate workobjects that are created on 2 threads and the creationcode of the workobject
is inside a dll which is loaded only once into my application.
Questions:
If I call exported functions from a dll, does the loadlibrary call which loaded the dll has to be called from within the context of the thread? I
don't think this is the case (see test b) ), but perhaps somebody knows better!?`Could this be causing my problems? If this is the case then there seems to be no way of using functions from one dll from multiple threads!?
Does anybody have an idea what causes these strange exceptions?
Any help/idea/explanation/suggestion greatly appreciated.
I found it. The Problem was, that i had to switch the delphi memorymanager to multithread mode with IsMultiThread := TRUE inside the dllcode! I already did this in the main application code, but the dll seems to use it's own version of the IsMultiThread flag or even it's own version of the delphi memorymanager. After adding IsMultiThread := TRUE to the dllcode everything works fine now.

Delphi - Thread not executing in ActiveX form - but does elsewhere

I have a thread, called TAlertThread. The thread interacts with its owner by triggering events. For example, when certain data is available inside the thread, it sets some temp variables and calls Synchronize(UpdateAlert) which in turn triggers the appropriate event.
Now the thread works perfectly in any standard windows application. My problem is when I put that thread inside of an ActiveX form (TActiveForm). The ActiveX control (aka COM object) is then embedded inside of a Windows Desktop Gadget (via HTML / Javascript). I also have experience with this, the gadget is not the issue. The ActiveX component works fine in its destination, except the thread is never executed. It's even being called EXACTLY the same way as I called it from the App.
Is this some limitation with ActiveX, blocking threads from executing? I wouldn't think so, because other things that require threads internally (such as TADOConnection) work. I am in fact properly calling CoInitialize and CoUninitialize appropriately. Again, works perfect in an application, but does not work at all in ActiveX.
Here is how I call this thread...
procedure TRMPDashXS.ExecThread;
begin
//Thread created suspended
lblStatus.Caption:= 'Executing Thread...';
fThread:= TAlertThread.Create(fConnStr); //fConnStr = connection string
fThread.Priority:= tpIdle;
fThread.OnConnect:= Self.ThreadConnected;
fThread.OnDisconnect:= Self.ThreadDisconnected;
fThread.OnBegin:= Self.ThreadStarted;
fThread.OnFinish:= Self.ThreadFinished;
fThread.OnAlert:= Self.ThreadAlert;
fThread.OnAmount:= Self.ThreadAmount;
fThread.Resume; //Execute the thread
end;
I suspect this might describe exactly what you're experiencing in your version of Delphi:
http://soft-haus.com/blog/2009/02/10/codegear-borland-activex-threading-synchronization-problems/
which references the same article you cited:
http://edn.embarcadero.com/article/32756
I'm not sure if that helps ... but I hope it does. At least a little :)
PS:
Is there any particular reason you have to use Com/ActiveX and/or TActiveForm?
According to this article here: http://edn.embarcadero.com/article/32756 web browsers don't allow threading via ActiveX. However that still doesn't explain why it doesn't work when I put it in a C# application.

C++ MultiThreading with visual studio express 2010 Forms Application

I am developing a Windows forms application which connects to a piece of hardware, acquires a lot of data (~1 GSample/sec), processes it, and spits it out to the screen upon a button click. I am now trying to automate the process in a loop that can be started/stopped at any time so I can monitor it whilst tweaking the input to the acquisition hardware. I thinks it's clear that I need to do this on a separate thread, but I'm having a heck of a time trying to do this in c++/cli - I have found a number of good examples using MFC, which is not supported by Express.
Specifically: My task is to press a button which is handled in Form1.h, to call a function in my main file Acquisition.cpp which contains the following code (currently an infinite loop)
void Form1::realTimeUpdate()
{
// live is a boolean variable set by a button on the form
while(live)
{
displayVariance(getVar(getQuadratures(100),nbrSamples));
}
}
I wish to execute this code in a separate thread so that the main program can listen for the user request to stop the operation. Without threading, I currently have to forcefully quit the program (or set it to run a fixed number of times) to stop it.
Is there any suggestions how I might go about running this code on a separate thread?
I've (unsuccessfully) tried a few things already:
Modifying the example given in This Microsoft Example. Problem: requires /clr:oldSyntax option which is incompatible with the other 1300 lines of code in the program.
Trying to do what I'd do in Java (Declare a global thread and start/stop it from any point in the code. Problem: Compiler won't let me declare a global System::Threading.Thread
this beautiful example. Problem: Requires MFC.
Any suggestions would be greatly appreciated!
You can use a BackgroundWorker or a Thread to handle this. You'll need to make sure that the portion of your work that updates the UI is marshaled back to the UI thread, however.
Here is a tutorial on threading in C++/CLI.
For the record, upon Reed's suggestion about using a BackgroundWorker, I sifted through the code at the bottom of this page and modified my code so that:
It created a new backgroundWorker BGWorker in which BGWorker->DoWork() called my realTimeUpdate() function.
A button on the main Form calls either RunWorkerAsync() or CancelAsync() depending on whether or not the process is running (checked by a boolean flag in my main program).
The realTimeUpdate() function is now passed a BackgroundWorker - realTimeUpdate(BackgroundWorker^ worker, DoWorkEventArgs ^ e) After each calculation is complete within the internal loop, it calls worker->ReportProgress(result) function. In the BGWorker->ProgressChanged() function a separate function, upDataUI(int) draws the result on the main form.
Thanks again for the help.

Resources