Link to home
Start Free TrialLog in
Avatar of olegsp
olegsp

asked on

Using CRITICAL_SECTION for different class instances

I have some
class ResourceUser
{
?
     // Pointer to some data used by this class instance
     void* m_pResourcePointer;    

     // Attach data pointer to the class instance
     void AttachResourcePointer(void* p)
     {
       if(!p) m_pResourcePointer = p;
     }

     // Do some resource processing
     void ProcessResource()
     {
      ::EnterCriticalSection(&m_CS);
      // Do something with m_pResourcePointer
      ::LeaveCriticalSection(&m_CS);
     }

     // Critical Section
     static CRITICAL_SECTION m_CS;

?
}
and I use several instances of this class in my program:
     ResourceUser RU1, RU2;
     RU1. AttachResourcePointer(p1);
     RU2. AttachResourcePointer(p2);
Here p1 and p2 are some resource pointers (FILE*, for example), used by the two instances of ResourceUser. The problem is that both RU1 and RU2 are accessed by several threads in my program, and to make it safe, I use critical section m_CS in methods like ProcessResource() as shown above. However, RU1 And RU2 are using different resources ? so, if I declare m_CS as static to make it globally unique, any thread access to RU1 resource will also block the RU2 resource ? I do not want this to happen. How can I fix that? What happens, for instance, if I remove ?static? from the m_CS declaration ? will this contradict the usage of CRITICAL_SECTION ? In other words, how do I declare/use the critical section in my class so that using it in one class instance will not block another class instance ?
I certainly do not want to declare several static m_CS1, m_CS2 etc. just to use each particular m_CSn for its instance only ? the number of class instances in use changes dynamically.
ASKER CERTIFIED SOLUTION
Avatar of ShaunWilde
ShaunWilde

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of robpitt
robpitt

It sounds to me like you would benifit from two critical sections.

The first for synchronised access to the shared data that m_pResourcePointer might point to.
And the second for synchronised access to an actual objects member data.

The second should be a normal class member. Arguably the first is actually a property of the shared data though this could be implemented as a static class member.

Rob
Avatar of olegsp

ASKER

>you can remove the static keyword
But if my critical section m_CS variable is not static (global), wouldn't every thread allocate its own copy of m_CS, making it thus useless ? This is something I do not know, please explain.


>you might make it easier to manage by binding the CS to >the resource object rather than the class that
>is using the resource
I thought about that, but I do not want to take this approach. My critical section code is a little bit more complex than just access to the resource pointer, so I need to keep the critical section variable in my ResourceUser class
> But if my critical section m_CS variable is not static
> (global), wouldn't every thread allocate its
> own copy of m_CS, making it thus useless ?

no if you made it a member of the class then you would have 1 CS per class - unless it was static then you would have 1 CS for all instances of the class

what scope you use for your critical section depends on the resource you are protecting

if the resource is 1 per class then you can use 1 CS per resource - if you use a resource between classes then you will need 1 CS per resource - so really it is 1 CS per resource

by resource I mean a collection of data (eg structure) or some other data that can only be accessed by 1 thread at a time
Avatar of olegsp

ASKER

Last question: is there a way to set a timeout value for the thread blocking ? I.e., when a thread is blocked at
     ::EnterCriticalSection(&m_CS);
it won't wait infinitely, and if the resource does not become available in some nTimeout seconds, the thread will exit without attempting to access the blocked resource?
I know one can do something like that with TryEnterCriticalSection(), but it is supported only on Win NT and 2000, I guess.
If you want to do this you can use Event object, ie CreateEvent(),
And then use WaitForSingleObject() with timeout and SetEvent() and ResetEvent() to change it's flag.
This would work on all OS's.
> TryEnterCriticalSection
the docs say it is unsupported but it does surprise me that this 1 CS related function isn't supported - even CE supports it. (the docs may be wrong - it wouldn't be the first time)

have a look at the exports of kernel32.dll on your 95/98/me machine and see if it is in there (use quick view and it might be ordinal 252)
It dosen't exist on the 95/8/me kernel32.dll (checked it).
I'd sugest you'd use the WaitForSingleObject() with Event Object, it's well documented, and works for me just fine!

Peeping again at your question.. even though you didn't mention what you want to do! using "Thread Local Storage" API might solve your problem in a more elegant way: Use TlsAlloc() and TlsSetValue(), TlsGetValue() to manage each thread private resource, and keep using the static CS to protect the global resource.