Win32( 线程控制_CONTEXT结构体)

1.线程控制

终止线程

方式一:ExitThread(结束码)

该函数在被调用过后,会告诉操作系统来关闭线程

结束码:ExitThread调用结束后,会返回一个结束码,我们可以通过这个结束码来判断线程是正常结束还是异常

一旦该函数被调用完毕,就会销毁堆栈

存在弊端:如果我们在堆栈中有mallc等分配空间的代码,一旦ExitThread函数执行后,就会销毁堆栈,因此我们分配的控件就得不到free的机会,那么就会存在内存泄露的风险

并且该函数,如果是放在回调函数中,那么系统结束的就是主线程,因此在我们的实验中,如果ExitThread函数是放在线程函数中,那么就是终止的线程,对话框DialogBox并没有消失

但是如果是放在回调函数中,那么主程序就会被终止,但是前面我们创建的线程却没有终止,所以就出现了程序未结束的情况

 方式二:线程函数返回

意思就是让线程函数正常销毁,在终止之前将要做的事,比如释放空间等代码写在终止进程之前

while (dwTimer<10000)
{
	if (dwTimer == 10)
	{
		break;
	}
	Sleep(0);
	memset(buffer, 0, sizeof(buffer));
	sprintf(buffer, "%d", ++dwTimer);

	SetWindowText(hEdit, buffer);		
}
//这里就可以写自己用来释放资源的代码

return 0;

方式三:::TerminateThread(hThread,2)

同步调用:ExitThread函数是在当前线程对线程进行终止的,一旦线程被终止,得到返回值,线程就结束了,ExitThread函数下面的代码就不会继续了

异步调用:这里TerminateThread函数是在另一个线程对当前线程进行终止,TerminateThread告诉操作系统终止当前线程后,就继续往下走了,即系统将线程终止前,代码可能会来到TerminateThread函数下面的代码,存在隐患,因此我们需要用到::WaitForSingleObject(hThread,INFINITE)函数

注意:该函数终止线程的时候不会销毁堆栈,因此存在问题

2.线程ConText结构体

思考:                            
                            
每个线程在执行的时候,都会独自占用一个CPU,当系统中的线程数量 > CPU的数量时,就会存在多个线程共用一个CPU                            
的情况。但CPU每次只能运行一个线程,Windows每隔20毫秒会进行线程的切换,那比如线程A执行到地址:0x2345678                            
eax:1 ecx:2 edx:3 ebx:4...还有eflag标志寄存器中的值等等。。。                            
此时,线程执行时间到了,被切换到了线程B。。。。当线程B的时间片也到了,再切换会线程A时,系统是如何知道该                            
从哪个地址开始执行呢?被切换前用到的各种寄存器的值该如何恢复呢?    

这时就要用到ConText结构体了,每次切换线程之前,系统就把当前各种寄存器的数据存入结构体中,下次又轮到该线程时,又可以根据前面的数据继续执行

CONTEXT:							
							
该结构包含了特定处理器的寄存器数据。							
							
							
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;							
							
						
							

首先我们要将线程挂起,否则线程仍在继续,那当前结构体中的数据就没有意义了

这里context.ContextFlags成员会根据我们不同的赋值,我们可以得到不同的成员

当赋值CONTEXT_FULL时,就包含debug寄存器以外的所有成员

赋值CONTEXT_DEBUG_REGISTERS加CONTEXT_FULL就可以包含所有成员

这里我们使用SetThreadContext函数可以修改系统中ConText结构体的值

3.作业

// CreateThread1.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "resource.h"
#include <stdio.h>
#include<Windows.h>

	HWND hEdit ;					
	DWORD WINAPI ThreadProc1(LPVOID lpParameter)					
	{					
		TCHAR szBuffer[10];				
		DWORD dwIndex = 0;				
		DWORD dwCount;				
						
		while(dwIndex<10000)				
		{				
			GetWindowText(hEdit,szBuffer,10);			
			sscanf( szBuffer, "%d", &dwCount );			
			dwCount++;			
			memset(szBuffer,0,10);			
			sprintf(szBuffer,"%d",dwCount);			
			SetWindowText(hEdit,szBuffer);			
			dwIndex++;			
		}				
						
		return 0;				
	}					
	DWORD WINAPI ThreadProc2(LPVOID lpParameter)					
	{					
		TCHAR szBuffer[10];				
		DWORD dwIndex = 0;				
		DWORD dwCount;				
						
						
		while(dwIndex<10000)				
		{				
			GetWindowText(hEdit,szBuffer,10);			
			sscanf( szBuffer, "%d", &dwCount );			
			dwCount++;			
			memset(szBuffer,0,10);			
			sprintf(szBuffer,"%d",dwCount);			
			SetWindowText(hEdit,szBuffer);			
			dwIndex++;			
		}				
						
		return 0;				
	}					
						
	BOOL CALLBACK MainDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)					
	{					
		BOOL bRet = FALSE;				
						
		switch(uMsg)				
		{				
		case WM_CLOSE:				
			{			
				EndDialog(hDlg,0);		
				break;		
			}			
		case WM_INITDIALOG:				
			{			
				hEdit = GetDlgItem(hDlg,IDC_EDIT1);		
				SetWindowText(hEdit,"0");		
						
				break;		
			}			
		case WM_COMMAND:				
						
			switch (LOWORD (wParam))			
			{			
			case IDC_BUTTON1:			
				{		
					HANDLE hThread1 = ::CreateThread(NULL, 0, ThreadProc1, 	
						NULL, 0, NULL);
						
					::CloseHandle(hThread1);	
					return TRUE;	
				}		
			case IDC_BUTTON2:			
				{		
					HANDLE hThread2 = ::CreateThread(NULL, 0, ThreadProc2, 	
						NULL, 0, NULL);
						
					::CloseHandle(hThread2);	
					return TRUE;	
				}		
			}			
			break ;			
		}				
						
		return bRet;				
	}					
						
	int APIENTRY WinMain(HINSTANCE hInstance,					
	                     HINSTANCE hPrevInstance,					
	                     LPSTR     lpCmdLine,					
	                     int       nCmdShow)					
	{					
	 	// TODO: Place code here.				
						
		DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG_MAIN),NULL,MainDlgProc);				
						
		return 0;				
	}					

一个cpu只能运行一个线程,当多个线程使用一个cpu时,就需要通过快速的切换进程来实现进程之间的多个运行,因此在该代码中,如果每个线程的运行时间较短,能够快速结束时,那么对于进程就没有太大影响

但是如果每个线程运行时长都比较长时,在这期间,如果用户点击按钮触发了另一个线程,就会出现线程之间抢占的现象,但是抢占之后系统并不会自动切换到另一个未完成的线程那里,就导致了错误的发生

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值