有关TLS的一点理解

源代码
#include "stdafx.h"
#include <windows.h>

// 说明使用TLS
#pragma comment(linker, "/INCLUDE:__tls_used")


// 普通的全局变量
int globenum = 0xFFFFFFFF;

// TLS变量
__declspec ( thread ) int  gTLSnum= 0x11111111;
__declspec ( thread ) char g_szStr[ ] = "TLS gTLSnum= 0x%p ...\r\n";

// TLS回调函数A
void NTAPI t_TlsCallBack_A( PVOID DllHandle , DWORD Reason , PVOID Red ) {
    printf("t_TlsCallBack_A -> run回调函数被执行(进出线程都会执行)\r\n");
    if( DLL_THREAD_DETACH == Reason ) // 判断线程是否退出,如果线程退出则打印信息
        printf( "t_TlsCallBack_A -> ThreadDetach!\r\n" );
    return;
}

// TLS回调函数B
void NTAPI t_TlsCallBack_B( PVOID DllHandle , DWORD Reason , PVOID Red ) {
    printf("t_TlsCallBack_B -> run回调函数被执行(进出线程都会执行)\r\n");
    if( DLL_THREAD_DETACH == Reason ) // 如果线程退出则打印信息
        printf( "t_TlsCallBack_B -> ThreadDetach!\r\n" );

    // 判断是否被调试
    if( IsDebuggerPresent( ) ) {
        printf("被调试了,进程将会退出,直接运行EXE试试看\n" );
        system( "pause" );
        ExitProcess( 0 );
    }
    return;
}

/*
* 注册TLS回调函数,".CRT$XLB"的含义是:
* CRT表明使用C RunTime机制
* X表示标识名随机
* L表示TLS callback section
* B其实也可以为B-Y的任意一个字母
* 有一种说法是:编译器会按照这个字母的
* 顺序来将我们添加的段保存到pe文件中。
*/
#pragma data_seg(".CRT$XLB")
PIMAGE_TLS_CALLBACK p_thread_callback[ ] =//每一次进入退出线程时,都会执行此函数!!!!!
{
    t_TlsCallBack_A ,  // TLS线程回调函数
    t_TlsCallBack_B ,
    NULL
};
#pragma data_seg()

DWORD WINAPI t_ThreadFun( PVOID pParam ) {
    printf( "t_Thread ->  first printf:" );
    printf( g_szStr , gTLSnum);
    printf( "[1]普通的全局变量globenum :%08X\n" , globenum );

    globenum = 0;
    //注意这里
    // 将会有两个线程修改此处
    gTLSnum= 0x22222222;


    printf( "t_Thread -> second printf:" );
    printf( g_szStr , gTLSnum);
    printf( "[2]普通的全局变量globenum :%08X\n" , globenum );
    return 0;
}
/*
当一个线程被创建的时候
TLS线程回调函数和普通线程回调函数的执行顺序:
1. 先将TLS线程回调函数都调用完
1.1 TLS线程回调函数注册多少个,就调用多少个,而且按照定义的顺序调用
2. 再调用线程回调函数

当一个线程退出的时候
1. 将TLS线程回调函数都调用完
1.1 TLS线程回调函数注册多少个,就调用多少个,而且按照定义的顺序调用
*/

int _tmain( int argc , _TCHAR* argv[ ] ) {
    printf( "_tmain -> TlsDemo.exe is runing...\r\n\r\n" );
    HANDLE a = CreateThread( NULL , 0 , t_ThreadFun , NULL , 0 , 0 );


    //Sleep( 500 );  // 睡眠100毫秒用于确保第一个线程执行完毕
    //printf( "\r\n" );
    WaitForSingleObject(a, -1);
    CreateThread( NULL , 0 , t_ThreadFun , NULL , 0 , 0 );
    system( "pause" );
    return 0;
}
说明分析:

1.本函数只能使用ctrl+F5才能看出效果
IsDebuggerPresent( )这个函数可以测试出你有没有在用F5以及F10调试
这里写图片描述

对比这两组不同箭头的数值,结合源代码的执行流程

这里写图片描述

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值