Vc6 and VC. net2003 uses the single-threaded C Runtime Library by default. By 2005, the default value is multi-threaded, microsoft simply removed the single-line running switch. many people are curious about this, but do not know the specific differences between the two runtime libraries. in this regard, I start with the source code of the CRT. Taking the CRT of vc6 as an example, the analysis results are as follows:
When a Win32 application compiled by VC is executed, the winmain crtstartup function of C Runtime is called first,
Void winmaincrtstartup (void)
{
Int mainret;
/*
* Get the full Win32 version
*/
_ Osver = getversion ();
_ Winminor = (_ osver> 8) & 0x00ff;
_ Winmajor = _ osver & 0x00FF;
_ Winver = (_ winmajor <8) + _ winminor;
_ Osver = (_ osver> 16) & 0x00FFFF;
# Ifdef _ MT
If (! _ Heap_init (1)/* initialize heap */
# Else/* _ MT */
If (! _ Heap_init (0)/* initialize heap */
# Endif/* _ MT */
Fast_error_exit (_ RT_HEAPINIT);/* write message and die */
# Ifdef _ MT
If (! _ Mtinit ()/* initialize multi-thread */
Fast_error_exit (_ rt_thread);/* write message and die */
# Endif/* _ Mt */
......
We can see that the heap Initialization is different for the two versions. multithreading uses the 1 parameter to call the _ heap_init () function.
Next let's take a look at how _ heap_init () initializes the heap.
Int _ cdecl _ heap_init (
Int mtflag
)
{
// Initialize the "big-block" heap first.
If (_ crtheap = heapcreate (mtflag? 0: heap_no_serialize,
BYTES_PER_PAGE, 0) = NULL)
Return 0;
// Pick a heap, any heap
_ Active_heap = _ heap_select ();
If (_ active_heap = _ V6_HEAP)
{
// Initialize the small-block heap
If (_ sbh_heap_init (MAX_ALLOC_DATA_SIZE) = 0)
{
Heapdestroy (_ crtheap );
Return 0;
}
}
Else if (_ active_heap ==__ v5_heap)
{
If (_ old_sbh_new_region () = NULL)
{
Heapdestroy (_ crtheap );
Return 0;
}
}
Return 1;
}
The difference is that the HEAP_NO_SERIALIZE parameter is called in a single thread.
HANDLE HeapCreate (
DWORD FlOptions,// Heap allocation attributes
SIZE_T DwInitialSize,// Initial heap size
SIZE_T DwMaximumSize// Maximum heap size
);
This is the description of HEAP_NO_SERIALIZE in msdn,
| HEAP_NO_SERIALIZE |
Specifies that mutual exclusion will not be used when the heap functions allocate and free memory from this heap. the default, when HEAP_NO_SERIALIZE is not specified, is to serialize access to the heap. serialization of heap access allows two or more threads to simultaneously allocate and free memory from the same heap. |
It can be seen that the heap created by the library during multi-thread running allows two or more threads to allocate and release the memory in the same heap. Then the multi-thread library calls
Int _ cdecl _ mtinit (
Void
)
{
_ Ptiddata ptd;
/*
* Initialize the mthread lock Data Base
*/
_ Mtinitlocks ();
/*
* Allocate a TLS index to maintain pointers to per-thread data
*/
If (_ tlsindex = tlsalloc () = 0 xffffffff)
Return false;/* fail to load DLL */
/*
* Create a per-thread data structure for this (I. e., the startup)
* Thread.
*/
If (ptd = _ calloc_crt (1, sizeof (struct _ tiddata) = NULL) |
! TlsSetValue (_ tlsindex, (LPVOID) ptd ))
Return FALSE;/* fail to load DLL */
/*
* Initialize the per-thread data
*/
_ Initptd (ptd );
Ptd-> _ tid = GetCurrentThreadId ();
Ptd-> _ thandle = (unsigned long) (-1L );
Return TRUE;
}
Void _ cdecl _ mtinitlocks (
Void
)
{
/*
* All we need to do is initialize _ LOCKTAB_LOCK and _ EXIT_LOCK1.
*/
InitializeCriticalSection (_ locktable [_ LOCKTAB_LOCK]);
InitializeCriticalSection (_ locktable [_ EXIT_LOCK1]);
InitializeCriticalSection (_ locktable [_ HEAP_LOCK]);
Initializecriticalsection (_ locktable [_ signal_lock]);
}
The initializecriticalsection function is described as follows:
Initializecriticalsection
TheInitializeCriticalSectionFunction initializes a critical section object.
VOID InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection // critical section);
Parameters
-
LpCriticalSection
-
[Out] Pointer to the critical section object.
Return values
This function does not return a value.
In low memory situations,InitializeCriticalSectionCan raise a status_no_memory exception.
Remarks
The threads of a single process can use a critical section object for mutual-exclusion synchronization. there is no guarantee about the order in which threads will obtain ownership of the critical section, however, the system will be fair to all threads.
The process is responsible for allocating the memory used by a critical section object, which it can do by declaring a variable of TypeCRITICAL_SECTION. Before using a critical section, some thread of the process must callInitializeCriticalSectionOrInitializeCriticalSectionAndSpinCountFunction to initialize the object.
After a critical section object has been initialized, the threads of the process can specify the object inEnterCriticalSection,TryEnterCriticalSection, OrLeaveCriticalSectionFunction to provide mutually exclusive access to a shared resource. For similar synchronization between the threads of different processes, use a mutex object.
A critical section object cannot be moved or copied. the process must also not modify the object, but must treat it as logically opaque. use only the critical section functions to manage critical section objects. when you have finished using the critical section, callDeleteCriticalSectionFunction.
A critical section object must be deleted before it can be reinitialized. Initializing a critical section that has already been initialized results in undefined behavior.
Void _ cdecl _ initptd (
_ Ptiddata ptd
)
{
Ptd-> _ pxcptacttab = (void *) _ XcptActTab;
Ptd-> _ holdrand = 1L;
# Ifdef _ M_MRX000
/*
* MIPS per-thread data
*/
Ptd-> _ MipsPtdDelta =
Ptd-> _ MipsPtdEpsilon =-1L;
# Endif/* _ M_MRX000 */
}