I have a system that is multi-threaded. I want to create a object in a thread, and every object that runs in this thread can view this object.
Example,
When i use GetCurrentThreadID i always get same id, if i call it from the same thread.
I want to call, for example, getSharedObject and always see the same object if i call it from the same object. So I need to write this object in a memory location that any object inside the same thread can see this object.
Is there anyway to do that, using the Windows API? Or I have to do it by myself?
thanks!
If the variable where you save the object pointer is global, then any code in your thread can access it. And any code from any other thread can, too, for that matter.
If you want that each thread sees a different object, then you want Thread Local Storage.
See the win32 functions TlsAlloc, TlsSetValue, TlsGetValue and TlsFree.
See also __declspec( thread ) here.
Related
When I create a new thread in a program... in it's thread handle function, why do I pass variables that I want that thread to use through the thread function prototype as parameters (as a void pointer)? Since threads share the same memory segments (except for stack) as the main program, shouldn't I be able to just use the variables directly instead of passing parameters from main program to new thread?
Well, yes, you could use the variables directly. Maybe. Assuming that they aren't changed by some other thread before your thread starts running.
Also, a big part of passing parameters to functions (including thread functions) is to limit the amount of information the called function has to know about the outside world. If you pass the thread function everything it needs in order to do its work, then you can change the rest of the program with relative impunity and the thread will still continue to work. If, however, you force the thread to know that there is a global list of strings called MyStringList, then you can't change that global list without also affecting the thread.
Information hiding. Encapsulation. Separation of concerns. Etc.
You cannot pass parameters to a thread function in any kind of normal register/stack manner because thread functions are not called by the creating thread - they are given execution directly by the underlying OS and the API's that do this copy a fixed number of parameters, (usually only one void pointer), to the new and different stack of the new thread.
As Jim says, failure to understand this mechanism often results in disaster. There are numnerous questions on SO where the vars that devs. hope would be used by a new thread are RAII'd away before the new thread even starts.
I am developing an UI application that creates a COM object along the way.
The problem is, I want to "move" this COM object entirely on a different thread.
What I do is this:
create the new thread I want to move the object into (with CreateThread API)
after entering this thread, I'm calling PeekMessage to setup a message queue for it
calling CoInitialize, CoCreateInstance to create the COM object, QueryInterface to get the interface I want
finally I call a method on the interface that displays a MessageBox with the value returned by GetCurrentThreadId() (I have access to the VB6 code of the COM library within which the object resides).
The problem is, as this message box shows, the object methods are still executed on the original UI thread, not on the thread I created and done all those steps into. One more thing to mention, after calling the interface method, I'm also setting up a classic message loop in it.
How can I change this behaviour and achieve what I want? (that is, I want the COM object calls that originate from my newly created thread to be executed ON IT, not on the original application thread)
Here's some pseudocode to make it even more clearer:
void myMainUIMethod(){
MessageBox(GetCurrentThreadId()); // displays 1
CreateThread(&myCOMObjectThreadProc);
}
void myCOMObjectThreadProc(){
MessageBox(GetCurrentThreadId()); // displays 2
CoInitialize(NULL);
myObject = CoCreateInstance(myObjectsCLSID);
myObjectInterface = myObject->QueryInterface(myObjectInterfaceCLSID);
myObjectInterface->showThreadIDMessageBox(); // this would be the COM object method call
}
And, in the VB6 code of the object, here's the pseudo-definition of showThreadIDMessageBox.
Public Sub showThreadIDMessageBox()
Call MessageBox(GetCurrentThreadId()) //displays 1, I want it to display 2
End Sub
I have achieved what I wanted by CoUninitalizing on the main thread, before creating the new thread. But why does this happen? If COM was initialized ON THE MAIN THREAD before I'm creating the new thread, maybe for some reason it had to be..I would't want the application to crash later because I had to call CoUninitialize before creating my new thread. Here's some pseudocode that illustrates that whichever thread calls CoInitialize first will be the one picked by the STA objects.
void myMainUIMethod(){
MessageBox(GetCurrentThreadId()); // displays 1
CoUninitialize(); // uninitialize COM on the main thread
CreateThread(&myCOMObjectThreadProc);
***i: MessageBox("When you want to initialize COM on main thread, confirm this");
CoInitialize();
}
void myCOMObjectThreadProc(){
MessageBox(GetCurrentThreadId()); // displays 2
***ii: MessageBox("When you want to initialize COM on the new thread, confirm this");
CoInitialize(NULL);
myObject = CoCreateInstance(myObjectsCLSID);
myObjectInterface = myObject->QueryInterface(myObjectInterfaceCLSID);
myObjectInterface->showThreadIDMessageBox(); // this shows 2 IF ***ii is confirmed before ***i, 1 otherwise
}
Thank you very much in advance,
Corneliu
Looks like your problem is that your COM component threading model is not specified in registry key InprocServer32. This means that object is considered as STA (single-threaded apartment) but will be loaded to main (or host) STA, not the STA that created it. This is the first thread that called CoInitialize. To be created in same STA that called CoCreateInstance you must create HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{Your CLSID}\InprocServer32#ThreadingModel registry value and set it to Apartment.
Quote from MSDN (InprocServer32 registry key documentation):
If ThreadingModel is not present or is not set to a value, the server is loaded into the first apartment that was initialized in the process. This apartment is sometimes referred to as the main single-threaded apartment (STA). If the first STA in a process is initialized by COM, rather than by an explicit call to CoInitialize or CoInitializeEx, it is called the host STA. For example, COM creates a host STA if an in-process server to be loaded requires an STA but there is currently no STA in the process.
I have finally achieved what I wanted! Adding a CoUninitialize call in the main UI thread, before creating the new thread has solved it. This happens because STA COM objects will be handled on the thread that first calls CoInitialize. Now all the calls to the objects methods are reported to be executed on the thread I created and the main window of the object (the COM component has a Form) is reported to belong to it too! (used WinSpy++ to test that).
There is still a question (and a problem) though..why does it behave this way?
Everywhere I search on the internet I see answers telling that a STA COM component will be fully executed on the thread it is created on (provided that CoInitialize or CoInitializeEx with COINIT_APARTMENTTHREADED had been called before), no matter what. Why does it matter if I called CoInitialize on another thread before..that's just plain stupid in my opinion for Microsoft to do so :), plus it might damage the future behaviour of my application, as I stated before.
EDIT: The correct answer is the one posted by Frost. Thank you again.
The threads are running in parallel and that's what they are meant to do. you need to synchronize between the two threads if you want one object to wait for some operation on other thread to complete. Event object will serve for your purpose.
You need to choose Free Threading as the Threading Model of the COM class when creating it. With C++ ATL, this is an option in the wizard when you select New -> COM class (or something like it). In .NET languages, I think this is specified as an attribute in the class.
BTW, you don't need to call QueryInterface after CoCreateInstance (unless you need more than one interface pointer). Just pass the GUID of the interface you want as the 4th parameter to CoCreateInstance.
Ah, I think I might know the problem now: it sounds like the VB6 COM object you are creating was registered as single-threaded, not apartment-threaded; this means that the object gets created on whichever thread is your app is the first to call CoInitialize().
This explain the behavior you are seeing: if you let your main thread CoInitialize() first, it becomes the "main thread" as far as COM is concerned, so the CoCreate ends up creating the object on it, even though it's CoCreated on a different thread. (This is only the case for single-threaded objects.)
But when you let your other thread CoInitialize() first, it is the "main thread" for COM, so the object gets created where you want it.
Can you change the threading model of your VB object to apartment instead of single? This would enable it to get created on the thread that calls CoCreate().
The problem is, I cannot change the threading model of the VB6 component since it is already used in other applications and it might damage it's behaviour.
...looks like that won't work for you. I guess you can check what the current threading model is, and if you can confirm that it's single, then you'll have an explanation for why it behaves the way it does, which might help you work with it.
--
So why does COM behave that way? - A: legacy compat issues. The Single Thread model is a holdover from before windows had threads in the first place, when every process had just one thread, and code didn't have to make any assumptions about synchronizations between objects within a process. To preserve this illusion and allow objects that were written assuming single-threaded COM to be used in a multithreaded environment, COM introduced the 'single' model, also known as 'legacy STA'. More details on this page, scroll down or search for "Legacy STA" for the details. COM basically puts all of these 'single' objects on the same [STA] thread - and uses whichever thread just happens to be the first to call CoInitialize. When you CoUninit and CoInit again on another thread, you're essentially restarting COM; so it's now the second thread that is the new "first thread to call CoInit", so that's why COM then ends up using that one...
(Legacy STA is such an old issue is was actually hard to track down any details; nearly all other articles mention apartment, free and both options; but there's rarely details about 'single'.)
They seem to perform a reasonably similar task: launching a new thread that performs that selector quickly and easily. But are there any differences? Maybe with regards to memory management?
Both are identical.
In iOS and Mac OS X v10.5 and later, all objects have the ability to spawn a new thread and use it to execute one of their methods. The performSelectorInBackground:withObject: method creates a new detached thread and uses the specified method as the entry point for the new thread. For example, if you have some object (represented by the variable myObj) and that object has a method called doSomething that you want to run in a background thread, you could could use the following code to do that:
[myObj performSelectorInBackground:#selector(doSomething) withObject:nil];
The effect of calling this method is the same as if you called the detachNewThreadSelector:toTarget:withObject: method of NSThread with the current object, selector, and parameter object as parameters. The new thread is spawned immediately using the default configuration and begins running. Inside the selector, you must configure the thread just as you would any thread. For example, you would need to set up an autorelease pool (if you were not using garbage collection) and configure the thread’s run loop if you planned to use it. For information on how to configure new threads
I presume they are the same, as - (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg; is defined in NSThread.h in the NSObject (NSThreadPerformAdditions) category. That is nothing conclusive, but that is evidence in that direction.
I've perused the MSDN documentation and I couldn't find a statement one way or the other. What I'm interested in is:
Can I call GdiplusStartup() on one thread and then use Gdiplus on another thread? Or do I need to call GdiplusStartup() for each thread?
If I have a Bitmap object on thread 1 and different one on thread 2, can they both call Bitmap::DrawImage() at the same time, or do I need to add locking to ensure serialization?
Thanks.
Partial answer of question 2, according to MSDN - Security Considerations: GDI+:
Thread Synchronization
It is possible for more than one
thread to have access to a single GDI+
object. However, GDI+ does not provide
any automatic synchronization
mechanism. So if two threads in your
application have a pointer to the same
GDI+ object, it is your responsibility
to synchronize access to that object.
Some GDI+ methods return ObjectBusy if
a thread attempts to call a method
while another thread is executing a
method on the same object. Do not try
to synchronize access to an object
based on the ObjectBusy return value.
Instead, each time you access a member
or call a method of the object, place
the call inside a critical section, or
use some other standard
synchronization technique.
The MSDN documentation states 'You can call GdiplusStartup on one thread and call GdiplusShutdown on another thread', which would indicate that you only need to call GdiplusStartup() once for your process (and use it from any thread).
I'm not sure about question 2. (I think what you meant was can you call Graphics::DrawImage( bitmap ) at the same time?) You would create a different Graphics class in each thread, right? So there should be no problem.
I want a function like GetCurrentThread which returns a TThread object of the current executing thread. I know there is a Win32 API call GetCurrentThread, but it returns the thread Id. If there is a possibility to get TThread object from that ID that's also fine.
From your own answer, it seems maybe you only want to "determine if running in the main thread or not", in which case you can just use
if Windows.GetCurrentThreadId() = System.MainThreadID then
// ...
Although this won't work from a DLL created with Delphi if it was loaded by a worker thread.
The latest version of Delphi, Delphi 2009, has a CurrentThread class property on the TThread class.
This will return the proper Delphi thread object if it's a native thread. If the thread is an "alien" thread, i.e. created using some other mechanism or on a callback from a third party thread, then it will create a wrapper thread around the thread handle.
I'm using my own TThread descendent that registers itself in a global list, protected with a lock.
That way, a method in this descendent can walk the list and get a TThread give an ID.
Answering my own question. I guess it is not possible to get TThread object from ID. It is possible by using a global variable. Then comparing its handle and current thread id, one can determine if running in the main thread or not.
Wouldn't the current executing thread be the one you're trying to run a function from?
You could store the pointer of the TThread instance in the current thread's context via the TlsSetValue API call and then retrieve it using TlsGetValue. However, note that this will only work if you're trying to retrieve/store the TThread instance of the current thread.