• 线程控制


    1.线程控制
    控制线程状态的API函数:
    //挂起线程:                
    ::SuspendThread(hThread);                
                    
    //恢复线程:                
    ::ResumeThread(hThread);                
                    
    //终止线程:                
        //方式一:                
        ::ExitThread(DWORD dwExitCode);  
            //参数中没有线程句柄,在线程函数中使用;
            //参数dwExitCode为线程退出码,将作为线程处理函数的返回值,用来描述线程的非正常退出
            //每一个线程都有自己的堆栈,该函数终止的线程会清理堆栈;
            //该函数一旦调用,线程将不能再被操作,但该函数并不会释放堆中的内存,因此存在内存溢出的隐患;  
           
        //方式二:线程函数返回   
           //线程函数执行完后会结束线程,因为是正常结束,可以自己写代码来释放堆中申请的内存;              
                    
        //方式三:                
        ::TerminateThread(hThread,2);    //第二个参数为线程退出码                
        ::WaitForSingleObject(hThread,INFINITE); 
            //TerminateThread并不会清理堆栈,这样的好处是其它地方用堆栈中的变量时不会出问题;     
               
    //判断线程是否结束                
    BOOL GetExitCodeThread(                
      HANDLE hThread,                
      LPDWORD lpExitCode                
    );                
        //STILL_ACTIVE //正在运行                
        //参数:                                
            //hThread: 要结束的线程句柄                                
            //dwExitCode: 指定线程的退出代码。可以通过GetExitCodeThread来查看一个线程的退出代码         
    ExitThread和TerminateThread的区别:
        都是用来结束线程的,ExitThread是同步的,也就是ExitThread执行完后程序才能继续往下执行;
        TerminateThread是异步调用;也就是单独起了一个线程来让目标线程结束; 
        TerminateThread调用后不能保证立即结束线程,在后面写线程结束后要执行的代码可能有问题;
        解决办法是用 WaitForSingleObject,该函数会阻塞线程直到TerminateThread的目标线程真正结束;
     
    线程挂起后恢复时并不会立即运行;
    因为windows并不是实时的操作系统,只有在调度程序给可调度状态的线程分配cpu时间时才会运行;
    因此windows中无法实现在某个确定的时间点运行一个线程;
     
    2.线程contex结构
    每个线程在执行的时候,都会独自占用一个CPU,
    当系统中的线程数量 > CPU的数量时,就会存在多个线程共用一个CPU的情况。
    但CPU每次只能运行一个线程,Windows每隔20毫秒会进行线程的切换,
    那比如线程A执行到地址:0x2345678 eax:1 ecx:2 edx:3 ebx:4...还有eflag标志寄存器中的值等等。。。             
    此时,线程执行时间到了,被切换到了线程B。。。。
    当线程B的时间片也到了,再切换回线程A时,系统是如何知道该从哪个地址开始执行呢?被切换前用到的各种寄存器的值该如何恢复呢?
     
    context结构:该结构包含了特定cpu的寄存器数据
    typedef struct _CONTEXT {                            
                                
        //                            
        // The flags values within this flag control the contents of                            
        // a CONTEXT record.                            
        //                            
        // If the context record is used as an input parameter, then                            
        // for each portion of the context record controlled by a flag                            
        // whose value is set, it is assumed that that portion of the                            
        // context record contains valid context. If the context record                            
        // is being used to modify a threads context, then only that                            
        // portion of the threads context will be modified.                            
        //                            
        // If the context record is used as an IN OUT parameter to capture                            
        // the context of a thread, then only those portions of the thread's                            
        // context corresponding to set flags will be returned.                            
        //                            
        // The context record is never used as an OUT only parameter.                            
        //                            
                                
        DWORD ContextFlags;                            
                                
        //                            
        // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is                            
        // set in ContextFlags.  Note that CONTEXT_DEBUG_REGISTERS is NOT                            
        // included in CONTEXT_FULL.                            
        //                            
                                
        DWORD   Dr0;                            
        DWORD   Dr1;                            
        DWORD   Dr2;                            
        DWORD   Dr3;                            
        DWORD   Dr6;                            
        DWORD   Dr7;                            
                                
        //                            
        // This section is specified/returned if the                            
        // ContextFlags word contians the flag CONTEXT_FLOATING_POINT.                            
        //                            
                                
        FLOATING_SAVE_AREA FloatSave;                            
                                
        //                            
        // This section is specified/returned if the                            
        // ContextFlags word contians the flag CONTEXT_SEGMENTS.                            
        //                            
                                
        DWORD   SegGs;                            
        DWORD   SegFs;                            
        DWORD   SegEs;                            
        DWORD   SegDs;                            
                                
        //                            
        // This section is specified/returned if the                            
        // ContextFlags word contians the flag CONTEXT_INTEGER.                            
        //                            
                                
        DWORD   Edi;                            
        DWORD   Esi;                            
        DWORD   Ebx;                            
        DWORD   Edx;                            
        DWORD   Ecx;                            
        DWORD   Eax;                            
                                
        //                            
        // This section is specified/returned if the                            
        // ContextFlags word contians the flag CONTEXT_CONTROL.                            
        //                            
                                
        DWORD   Ebp;                            
        DWORD   Eip;                            
        DWORD   SegCs;              // MUST BE SANITIZED                            
        DWORD   EFlags;             // MUST BE SANITIZED                            
        DWORD   Esp;                            
        DWORD   SegSs;                            
                                
        //                            
        // This section is specified/returned if the ContextFlags word                            
        // contains the flag CONTEXT_EXTENDED_REGISTERS.                            
        // The format and contexts are processor specific                            
        //                            
                                
        BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];                            
                                
    } CONTEXT;                            
                                
     
    进程就是程序的4GB空间,线程就是EIP;
    当一个线程切换时,为了再次执行时能接着执行,会将寄存器的信息保存context结构中;
     
    如何获取context结构中的值:
    例如:获取context中的eip
    //挂起线程;不挂起获取的值不准确                    
    SuspendThread(线程句柄);                    
                        
    CONTEXT context;                        
                        
    //设置要获取的类型                    
    context.ContextFlags = CONTEXT_CONTROL;                    
                        
    //获取                    
    BOOL ok = ::GetThreadContext(hThread,&context);                    
                        
    //设置                    
    context.Eip = 0x401000;     
                   
    SetThreadContext(hThread,&context);         

     3.线程控制实例代码

    #include "windows.h"
    #include "stdio.h"
    #include "resource.h"
    
    HWND plus;
    HANDLE hThread;
    
    //线程函数
    DWORD WINAPI doPlus(LPVOID param){
        //获取文本框内容
        TCHAR szBuffer[10];
        memset(szBuffer, 0, 10);
        GetWindowText(plus, szBuffer, 10);
        
        //字符串转数字
        DWORD num;
        sscanf(szBuffer, "%d", &num);
    
        //计算后写回文本框
        while(num < 1000){
            memset(szBuffer, 0, 10);
            Sleep(1000);
            sprintf(szBuffer, "%d", ++num);
            SetWindowText(plus, szBuffer);
        }
        return 0;
    }
    
    //回调函数
    BOOL CALLBACK DialogProc(                                    
                             HWND hwndDlg,  // handle to dialog box            
                             UINT uMsg,     // message            
                             WPARAM wParam, // first message parameter            
                             LPARAM lParam  // second message parameter            
                             )            
    {    
        switch(uMsg)                                
        {    
        case WM_INITDIALOG :
            plus = GetDlgItem(hwndDlg, IDC_EDIT1);
            SetWindowText(plus, TEXT("0"));
            return TRUE;      
                                        
        case  WM_COMMAND :                                
            switch (LOWORD (wParam))                            
            {
            case IDC_BTN_START:  
                hThread = ::CreateThread(NULL, 0, doPlus, NULL, 0, NULL);
                return TRUE;  
            case IDC_BTN_WAIT:
                ::SuspendThread(hThread);                
                return TRUE;
            case IDC_BTN_RETURN:
                ::ResumeThread(hThread);                
                return TRUE;
            }
            break ;   
            
        case WM_CLOSE:
            EndDialog(hwndDlg, 0);
            return TRUE;
        }    
                                        
        return FALSE ;                                
    }
    
    int CALLBACK WinMain(
                         HINSTANCE hInstance,
                         HINSTANCE hPrevhInstance,
                         LPSTR lpCmdline,
                         int nCmdShow
                         ){
        DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, DialogProc);
    
        return 0;
    }

    结果:

             
  • 相关阅读:
    品尝阿里云容器服务:负载均衡与容器的关系
    基于微服务架构、运行于容器中的.NET Core示例应用eShopOnContainers
    基于VS2017的Docker Support体检ASP.NET Core站点的Docker部署
    用工厂模式解决ASP.NET Core中依赖注入的一个烦恼
    终于知道什么情况下需要实现.NET Core中的IOptions接口
    ASP.NET Core Web API处理HttpResponseMessage类型返回值的问题
    ASP.NET Core奇遇记:无用户访问,CPU却一直100%
    省一行是一行:在if语句中使用C# 7.0的模式匹配
    ASP.NET Core 2.0 Preview 1 中贴心的新特性
    .NET Core类库项目中如何读取appsettings.json中的配置
  • 原文地址:https://www.cnblogs.com/ShiningArmor/p/12101363.html
Copyright © 2020-2023  润新知