Click to See Complete Forum and Search --> : A silly question on critical sections and threads


Granite Golem
February 20th, 2003, 05:29 AM
Sorry for such a question, but I've read MSDN already and searched through the forums...
I want to make a console application (so no MFC, only API functions) that organizes a second thread (for short time, not the entire process lifetime) and uses some data passed from the main thread. I found that passing of these data can be made through critical sections. But how can I use it? Those dumb examples in MSDN didn't clarify the way for me... :( How can I create a shareable data structure (some 3-4 fields)? Where have I to put this CRITICAL_SECTION variable and initialize it? I saw that I can pass a pointer to my structure with data during creating the second thread. But how to lock it for preventing cross-reading? Make a global variable?
I'm not a newbie in programming, but it's my first encounter with multithreading...
Thanks in advance.

Horst
February 20th, 2003, 08:01 AM
Hey Golem,

not that silly your question.

All global variables of the main program can be accessed by the thread. The only thing you need the critical section for is when both the program and the thread access these variables at once.

So you got at least two methods to access data in a thread.

1) You can pack the data in a single piece of global memory (You can reserve that with GlobalAlloc, etc.) and send a pointer to the thread when you call CreateThread, etc. (There is one reserved in that call just dont't nail me on it's name)
Don't forget to cleanup when you don't need the memory any longer. Resource leaks can slow your program dramatically. (I know I've seen it.)

2) You can simply access a global variable in your thread.


In case 2 you either have to know that it's no risk to access the data or you have to encase the access positons in your program and your thread with EnterCriticalSection and LeaveCriticalSection

Hope this helped you

Horst

galathaea
February 20th, 2003, 02:15 PM
Originally posted by Granite Golem
How can I create a shareable data structure (some 3-4 fields)? Where have I to put this CRITICAL_SECTION variable and initialize it? I saw that I can pass a pointer to my structure with data during creating the second thread. But how to lock it for preventing cross-reading? Make a global variable?
A nice way to do this without having to sprinkle the CRITICAL_SECTIONs throughout all of the code that uses these variables is to make a class that controls access to the variables with methods like ReadX() and WriteX(someX) (or more traditionally GetX / SetX). The class will also hold your synchronization object (CRITICAL_SECTION) and use it in its methods. Then, you can make a global instance of your object that any thread can access. Or, if you are working in a team and are afraid someone might try to make more instances of the object type, make it a singleton.

Also, its important to note that "cross-reading" does not need to be synchronized. Synchronization should be used when two threads are trying to write to the location or one thread is reading while the other is writing. But two threads reading will never cause a problem. Of course, if you don't want to go to the hassle of making a read/write lock, using a lock on all access is a safe alternative.

Granite Golem
February 21st, 2003, 08:47 AM
Thanks, I made some global variables.
But - it's rather weird, but it is a real fact - I can't call a COM-server's method through interface from my second thread! I initialize the interface in my main thread (CoCreateInstanceEx) and successfully call different methods from it. But when I try to use the global pointer to the interface from my second thread, it doesn't connect! And after some time it returns with error. I put breakpoints everywhere, both in client and COM-server, but nothing happens... And earlier it was with local variable from main thread, and I thought that it's because of locality. But with global interface it doesn't want to work too...

hankdane
February 21st, 2003, 04:40 PM
Originally posted by Granite Golem
I can't call a COM-server's method through interface from my second thread!

Did you call CoInitialize() from your thread?

JamesSchumacher
February 25th, 2003, 12:25 AM
If you need to read data from one thread in another, why are you using a CRITICAL_SECTION? - ANSWER: A critical section object blocks all threads except the owner.

Not an efficient method, but if you are using a global variable - this will guarantee that the data is not changed before it is read.

For efficiency, you should only block threads that *should* or *have to* be blocked. See 'mutexes', 'events', 'semaphores', etc....

Granite Golem
February 25th, 2003, 06:31 AM
Well, hankdane, I added CoInitialize - CoUninitialize, but no, seems it needs more... Maybe set my COM-server as singleton? And make CoCreateInstance from every thread?
JamesSchumacher: well, while I use my variables not at one time, it's okay with them. But in future very possibly I'll use these mutexes...

galathaea
February 25th, 2003, 02:28 PM
I wouldn't use mutexes for efficiency, since they too block all threads waiting on them and must drop down to ring0 to perform their action, making them much slower than CRITICAL_SECTIONs. Mutexes are important for interprocess synchronization, but I believe if all of the synchronization is occuring one application, you can acheive the same logic with both synchronization objects. If you are looking for efficiency, only enter the CRITICAL_SECTION or wait on the mutex when it is necessary, and use something like a read/write lock.

Kheun
February 25th, 2003, 08:38 PM
Originally posted by Granite Golem
I initialize the interface in my main thread (CoCreateInstanceEx) and successfully call different methods from it. But when I try to use the global pointer to the interface from my second thread, it doesn't connect!It seems like it is due to the threading model you have chosen for your COM object. If you are using Apartment thread, a object created by one thread cannot be used by another thread. If you like to share interface pointer between threads and even global object created within the COM between processes, you should try free threaded model. Also, every thread need to be CoInitializeEx(0, COINIT_MULTITHREADED) before it can call methods from the COM interface and subsequently CoUninitialize() when not using.

As for synchronization, the advice from the galathae is excellent. In fact, there is a CComAutoCriticalSection object provided by ATL.

"The COM and COM+ Programming Primer" from Prentice Hall PTR, written by Alan Gordon, is an excellent book for COM stuff.