Link to home
Start Free TrialLog in
Avatar of Axter
AxterFlag for United States of America

asked on

CCriticalSection and CMutex Diff

I'm trying to determine with *certainty* what is the difference between CCriticalSection and CMutex.

MSDN states the following:
Critical sections are used instead of mutexes (see CMutex) when speed is critical and the resource will not be used across process boundaries.

I'm reading that to mean you can use CCriticalSection if your code is not going to be accessed by multiple applications (via DLL).

My coworker is reading it to mean that the code is not going to be access by multiple instances.

class foo
{
 CCriticalSection m_CCriticalSection;
};

He thinks if you have multiple instances of foo, then you should be using CMutex instead of CCriticalSection.

Can someone give me a *good* explanation of the differences between CCriticalSection and CMutex?

Thanks
Avatar of jkr
jkr
Flag of Germany image

>>I'm reading that to mean you can use CCriticalSection if your code is not going to be accessed by multiple applications
>> (via DLL).
>>My coworker is reading it to mean that the code is not going to be access by multiple instances.

You are both right. Multiple instances of one process are in fact multiple processes. A critical section will only work in the address space of a process that created it and cannot be shared with another process, but it definitely is unique and valid for the whole process. Additionally, critical sections are "unnamed" and therefore only identified by their control structures in the memory location they reside in. Mutexes (as events) can have (but do not have to have) names and can be shared across process boundaries (if they are named) by referring to their unique name. Apart from that, mutexes are kerel objects will all bells and whisatles, whereas critical sections are a 'user land' construct.

If you have a critical section that is a class member, you will indeed end up instantiating one critical section for each class instance, unless you make that a static member.
BTW, here's a nice explanation by Jeffrey Richter: http://www.microsoft.com/msj/archive/S1DA0.aspx

--------------------------------------------------------->8--------------------------------

As you should know, critical sections and mutexes behave almost identically. However, mutexes have a few advantages over critical sections: mutexes can synchronize threads across process boundaries, you can wait on a mutex by specifying a timeout value, and mutexes notify a thread when they are abandoned. This is a nice list of mutex features that critical sections don't share. Why use a critical section instead of a mutex? There is only one answer: critical sections are faster. Mutex objects are kernel objects and as such the functions that manipulate them (WaitForSingleObject and ReleaseMutex) require the transition from user mode to kernel mode. This transition is on the order of 600 CPU instructions (on x86 processors).

Critical sections are not kernel objects and the implementations of EnterCriticalSection and LeaveCriticalSection exist almost entirely in user mode so the CPU does not transition to kernel mode. Calling these functions executes approximately 9 CPU instructions (on x86 processors). For threads making repeated calls to malloc and free, the performance hit from using kernel objects (like mutexes) versus critical sections can be quite noticeable and is certainly not desirable.

To be fair, critical sections do not execute entirely in user mode. As long as a thread does not attempt to acquire the critical section while another thread owns it, EnterCriticalSection and LeaveCriticalSection execute entirely in user mode as I mentioned. However, if a thread attempts to enter the critical section while it is owned by another thread, the critical section degrades to a kernel object and the thread executes 600 CPU instructions. However, in most applications it is rare that two (or more) threads contend for a critical section simultaneously, which still makes critical sections very useful.

--------------------------------------------------------->8--------------------------------


http://msdn.microsoft.com/library/en-us/dndllpro/html/msdn_onthefly.asp ("Synchronization on the Fly") gives some deeper insight to the whole area.
Avatar of Axter

ASKER

I'm sorry jkr, but your description sounded too similar to the MS description, which still leaves me with uncertainty.

>>If you have a critical section that is a class member, you will indeed end up instantiating one critical section for each class instance

Let's say I have three MAIN threads within the same application, and each MAIN thread has it's own instance of foo.
If thread #1 blocks {foo.m_CCriticalSection.Lock()}, is that block only effecting thread #1 (and sub threads of #1)?
Or does it also effect main threads #2 and #3?
Avatar of Axter

ASKER

Example:


UINT FileBridge::SendFileThread(LPVOID ptr)
{
  std::auto_ptr<foo> myfoo((foo*)ptr);
  myfoo->m_CCriticalSection.Lock(); //??????
}

Some code creating above thread:
AfxBeginThread(SendFileThread, new foo());//#1
AfxBeginThread(SendFileThread, new foo());//#2
AfxBeginThread(SendFileThread, new foo());//#3
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

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 Axter

ASKER

My coworker thinks above code will block on the second thread untill #1 thread calls an unlock.
Avatar of Axter

ASKER

>>If each thread has it's own instance of 'foo', you have three *different* instances of a critical section also, which are completely unrelated.

That's what I thought.  Now I just have to convince my coworker. :-)
>> My coworker thinks above code will block on the second thread untill #1 thread calls an unlock.

No. Definitely not. Let's simplify the situation:

class foo
{
int m_n;
};

UINT FileBridge::SendFileThread(LPVOID ptr)
{
 std::auto_ptr<foo> myfoo((foo*)ptr);
 myfoo->m_n = 42;
}

AfxBeginThread(SendFileThread, new foo());//#1
AfxBeginThread(SendFileThread, new foo());//#2
AfxBeginThread(SendFileThread, new foo());//#3

Will all instance of 'foo' be affected by the assignment?
Avatar of Axter

ASKER

Thanks
Avatar of Axter

ASKER

>>Will all instance of 'foo' be affected by the assignment?

He thinks that CCriticalSection crosses multiple instances of the same object.
Avatar of Axter

ASKER

It's so much easier when you can find clear Documentation to prove your case one way or another.
But when you have document that leaves room for interpretation, it makes it much harder to make a final unquestionable determination.
>>He thinks that CCriticalSection crosses multiple instances of the same object.

No, how could they? That would work with mutexes, but not when they're unnamed. However

class foo
{

foo() : m_CMutex(FALSE,"FOO_MUTEX") {}

CMutex m_CMutex;
};

can do that (if we make the appropriate things 'public', though :o)

The unique name would make it possible to share them accross objects, since the constructor would call 'OpenMutex()' after 'CreateMutex()' faild with 'ERROR_ALREADY_EXISTS' (at least I hope so, did not check with the sources, though)