一.理解系统内核对象
线程是系统内核对象之一.内核对象是系统内核分配的一个内存块,该内存块描述的是一个数据结构,其成员负责维护对象的各种信息.内核对象只能由系统内核来访问,应用程序无法在内存中找到这些数据结构并直接改变他们的内容。
常用的系统内核对象有事件对象、文件对象、作业对象、互斥对象、管道对象、进程对象和线程对象。
内核对象共性:
1.计数属性,内核对象在进程中被创建,但不被进程所拥有,当创建一个内核对象时,内核对象的使用计数为1,当其他进程访问该内核对象时,使用计数将递增1.当内核对象的使用计数为0,系统内核将撤销该对象。
2.安全属性,由安全描述符来表示。
二.使用CreateThread函数创建线程
HANDLE CreateThead(
LPSECURITY_ATTRIBUTES lpsa;
DWORD cdStack;
LPTHREAD_START_ROUTINE lpStartAddr;
LPVOID lpvThreadParam;
DWORD fdwCreate;
LPDWORD lplDThread);
DWORD __stdcall ThreadProc(LPVOID lpParameter)
lpsa:线程安全属性信息,如果为NULL,表示线程句柄不被子进程继承
cbStack:线程的栈大小,可以为0
lpStartAddr:线程函数,线程运行时将执行该函数
lpvThreadParam:传递到线程函数中的参数
fdwCreate:线程创建的标记
lpIDThread:一个整型指针,用于接收线程ID。如果参数为NULL,表示线程ID不被返回。
cbStack:线程的栈大小,可以为0
lpStartAddr:线程函数,线程运行时将执行该函数
lpvThreadParam:传递到线程函数中的参数
fdwCreate:线程创建的标记
lpIDThread:一个整型指针,用于接收线程ID。如果参数为NULL,表示线程ID不被返回。
{
CMultiThreadDlg* pDlg = (CMultiThreadDlg*)lpParameter;
CString str;
for (int i=0; i<99999;i++)
{
str.Format("%d",i);
pDlg->m_Edit.SetWindowText(str);
//pDlg->m_Edit.Invalidate();
}
return 0;
}
void CMultiThreadDlg::OnOK()
{
m_hThread = CreateThread(NULL,0,ThreadProc,this,0,NULL);
}
三.C++语言提供的_beginthreadex
uintptr_t _beginthreadex(void *security,unsigned stack_size,unsigned(*start_address)(void *),void *arglist.unsigned initflag,unsigned *thrdaddr);
security:线程安全属性信息,如果为NULL,表示线程句柄不被子进程继承
stack_size:现成的栈大小,可以为0
start_address:线程函数,线程运行时将执行该函数
arglist:传递到线程函数中的参数
initflag:线程的初始化标记,为0,表示线程立即执行线程函数,为CREATE_SUSPENDED。表示线程暂时被挂起
thrdaddr:一个整型指针,用于返回线程ID
要使用_beginthreadex函数,需要在工程中引用process.h头文件
unsigned int __stdcall ThreadProc(LPVOID lpParameter)
{
CMultyThreadDlg* pDlg = (CMultyThreadDlg*)lpParameter;
pDlg->m_Prog.SetRange32(0,999999);
for (int i=0; i<999999;i++)
{
pDlg->m_Prog.SetPos(i);
}
return 0;
}
void CMultyThreadDlg::OnOK()
{
m_hThread = (HANDLE)_beginthreadex(NULL,0,ThreadProc,this,0,NULL);
}
四.MFC应用程序中,可以使用AfxBeginThread函数
CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc,LPVOID pParam,int nPriority=THREAD_PRIORITY_NORMAL,UINT nStackSize=0,DWORD dwCreateFlags=0,LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);
CWinThread* AfxBeginThread(CRuntimeClass* pTreadClass,int nPriority=THREAD_PRIORITY_NORMAL,UINT nStackSize=0,DWORD dwCreateFlags=0,LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);
nParam:线程函数的参数
nPriority:现成的优先级
nStackSize:线程堆栈大小
dwCreateFlags:线程的创建标记
lpSecurityAttrs:线程的安全属性
pThreadClass:派生于CWinThread类的运行时类对象
UINT ThreadFun( LPVOID pThreadParam )
{
COperateThreadDlg* pDlg = (COperateThreadDlg*)pThreadParam;
pDlg->m_Prog.SetRange32(0,999999);
for (int i=0; i<999999;i++)
{
pDlg->m_Prog.SetPos(i);
}
return 0;
}
void COperateThreadDlg::OnOK()
{
m_pThread = AfxBeginThread(ThreadFun,this,0,0,0,NULL);
}
五.应用MFC类库创建线程
MFC类库提供的CWinThread类封装了对线程的支持。工作者线程和用户界面线程
1.m_bAutoDelete
该成员确定在线程终止时,线程对象是否自动被释放2.m_hThread
该成员表示线程对象关联的线程句柄3.m_nThreadID
该成员英语记录线程ID4.m_pMainWID
该成员表示应用程序的主窗口5.m_pActiveWnd
如果线程是OLE服务器的一部分,该成员表示容器应用程序住窗口6.CreateThread
该方法用于创建一个线程BOOL CreateThread(DWORD dwCreateFlags=0,UINT nStackSize=0,LPSECURITY_ATTRBUTES lpSecurityAttrs=NULL);
dwCreateFlags:线程的创建标识,如果为CREATE_SUSPENDED,线程在创建后立即挂起,直到调用ResumeThread方法才能开始执行线程函数,如果为0,线程创建后立即执行
nStackSize:线程堆栈的大小,如果为0,堆栈的大小将于主线程堆栈的大小相同
lpSecurityAttrs:线程的安全属性
7.GetMainWnd
该方法用于获取应用程序的主窗口指针,如果是OLE服务器应用程序,该方法返回的事m_pActiveWnd成员,否者返回m_pMainWnd成员virtual CWnd* GetMain();
8.ResumeThread
该方法用于重新唤醒线程,它将线程的挂起计数减1,如果线程的挂起计数为0,将开始执行线程DWORD ResumeThread();
9.SuspendThread
该方法用于挂起线程DWORD SuspendThread();
返回值:如果函数执行成功,返回为线程之前的挂起计数,否者为0xFFFFFFFF
六.线程的挂起、唤醒和终止
1.SuspendThread
该函数用于挂起线程DWORD SuspendThread(HANDLE hThread);
2.ResumeThread
该函数用于减少线程挂起的次数,如果线程挂起的次数为0,将唤醒线程DWORD ResumeThread(HANDLE hThread);
3.ExitThread
该函数用于结束当前的线程VOID ExitThread(DWORD dwExitCode);
4.TerminateThread
该函数用于强制终止线程的执行BOOL TerminateThread(HANDLE hTread,DWORD dwExitCode;
5.用于获取一个已中止线程的退出代码
BOOL GetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode);::OnCancel()
{
DWORD dwExit = 0;
if (m_pThread!= NULL)
{
GetExitCodeThread(m_pThread,&dwExit);
if (dwExit ==STILL_ACTIVE)
TerminateThread(m_pThread,0);
delete m_pThread;
}
CDialog::OnCancel();
}