关于VC的C运行时库的多线程版本和单线程版本的比较和分析

    VC6和VC.net2003默认使用单线程(Single-threaded)的C运行时库,到2005版本则默认为多线程(Multi-threaded),到了2008,微软索性把单线程运行时开关给去掉了.很多人对此很好奇,但不知道这两个运行时库具体有什么区别.对此,本人从crt源代码入手,以VC6的CRT为例,分析结果如下:

 

VC编译的Win32应用程序执行时,首先调用的并不是WinMain,而是C Runtime 的WinMainCRTStartup函数,


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 */

......

此处可以看到,两种版本的运行时堆的初始化是不相同的,多线程使用1参数调用_heap_init()函数

下面看看_heap_init()如何初始化堆

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;
}

可以看到,不同点在于单线程使用了HEAP_NO_SERIALIZE参数调用了

HANDLE HeapCreate(
  DWORD
flOptions,       // heap allocation attributes
  SIZE_T dwInitialSize// initial heap size
  SIZE_T dwMaximumSize   // maximum heap size
);

函数,msdn中对于HEAP_NO_SERIALIZE是这样描述的,

HEAP_NO_SERIALIZESpecifies 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.

可见,多线程运行时库创建的堆允许两个以上线程在相同的堆中同时分配和释放内存.之后多线程库调用

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()) == 0xffffffff )
            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] );

}
关于InitializeCriticalSection函数解释如下

InitializeCriticalSection

The InitializeCriticalSection function 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, InitializeCriticalSection can 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 type CRITICAL_SECTION. Before using a critical section, some thread of the process must call the InitializeCriticalSection or InitializeCriticalSectionAndSpinCount function to initialize the object.

After a critical section object has been initialized, the threads of the process can specify the object in the EnterCriticalSection, TryEnterCriticalSection, or LeaveCriticalSection function 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, call the DeleteCriticalSection function.

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 */
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值