创建线程的方式
一、创建线程的三种方式
1. CreateTread
函数的具体格式如下:
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadID
);
参数说明:
参数 | 说明 |
---|---|
lpThreadAttrivutes | 指向SECURITY_ATTRIBUTES的指针,用于定义新线程的安全属性,一般设置成NULL |
dwStackSize | 分配以字节数表示的线程堆栈的大小,默认值是0 |
lpStartAddress | 指向一个线程函数地址。每个线程都有自己的线程函数,线程函数是线程具体的执行代码 |
lpParameter | 传递给线程函数的参数 |
dwCreationFlags | 表示创建线程的运行状态,其中CREATE_SUSPEND表示挂起当前创建的线程,而0表示立即执行当前创建的进程 |
lpThreadID | 返回新创建的线程的ID编号 |
返回值:
成功返回新线程的句柄,失败返回NULL
①线程函数
- 线程函数的声明
必须是全局函数或者是静态成员函数。这里使用全局变量
DWORD WINAPI ThreadProc(LPVOID lpParam);//主要是放入线程中的函数
- 声明传入参数
为了传入多个参数,这里我们一般是采用结构体的。
//为了传递多个参数,采用结构体
struct threadInfo
{
HWND hWnd; //窗口句柄
....
....
};
- 类中定义
protected:
HANDLE hThread[4];//用来存储线程句柄
DWORD dwThreadID[4];//用于存放线程的ID
threadInfo Info[3];//用于传递线程所需要的参数
- 创建线程
for (int i = 0; i < 3; i++)
{
hThread[i] = CreateThread(NULL, 0, ThreadProc, &Info[i], 0, &dwThreadID[i]);
//注意不需要使用,需要释放
CloseHandle(hThread[i]);
}
2. 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* pThreadClass,
int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
);
参数说明:
参数 | 说明 |
---|---|
pfnThreadProc | 指向工作线程的控制函数。不能是NULL。这个函数必须按下面的方式定义;UINT MyControllingFunction( LPVOID pParam ); |
pThreadClass | 从CWinThread继承的对象的RUNTIME_CLASS。 |
pParam | 将要传送给控制函数的参数,如pfnThreadProc中定义的函数参数所示。 |
nPriority | 设定的线程的优先级。如果为0,则使用与创建它线程相同的优先级。 |
nStackSize | 指定新线程使用的栈的以字节为单位的大小。如果为0,则缺省的栈大小与创建它的线程的栈大小相同。 |
dwCreateFlags | 指定控制线程的创建过程的附加标志。这个标志可以是两个值之一: ① CREATE_SUSPENDED 经过一个延迟后启动这个线程。这个线程将在调用ResumeThread 以后才会启动。 ② 0 创建后立即启动这个线程。 |
lpSecurityAttrs | 指向一个SECURITY_ATTRIBUTES结构,它指定了线程的安全特性。如果为空,将使用与创建它的线程相同的安全特性。如果需要获得有关这个结构的详细信息 |
返回值:
指向新创建的线程对象的指针。
AfxBeginThread创建一个新的CWinThread对象,调用它的CreateThread函数以启动这个线程,并且返回这个线程的指针。整个过程都进行检查以保证如果创建失败,所有的对象都会被适当地释放。为了结束这个线程,可以在线程内调用AfxEndThread,或者从工作线程的控制函数内返回。
②线程函数
- 线程函数的声明
必须是全局函数或者是静态成员函数。一般使用静态成员函数作为线程传入整个类对象
//定义全局
UINT MyThreadFunction(LPVOID pParam);
//类中的静态成员
protected:
static UINT MyThread(LPVOID pParam);
- 创建线程
for (int i = 0; i < 3; i++)
{
//线程函数调用主对话框类的成员:线程函数的参数起着决定性作用!
CWinThread *pThread = AfxBeginThread(MyThread, this);//使用this
//CWinThread *pThread = AfxBeginThread(MyThreadFunction, &Info[i]);
//不需要释放
}
//线程函数的方法
UINT CThreadDlg::MyThread(LPVOID pParam)
{
CThreadDlg *pDlg = (CThreadDlg *)pParam;
int tipMsg = pDlg->Info->nOffset; //访问类中的变量
CString strTipMsg;
while (TRUE)
{
strTipMsg.Format(_T("%d"), tipMsg);
OutputDebugString(strTipMsg);//输出
Sleep(50);
}
return 0;
}
系统调试信息输出的捕获工具:
DebugView是一个系统调试信息输出的捕获工具。
在程序中使用如下函数:
1> OutputDebugString
或者在MFC
中使用TRACE
2> 内核模式中使用Out_Debug_String,DbgPrint ,_Debug_Printf_Service
编译程序为DEBUG
版本,然后运行程序(不是在vs
中运行,是单独运行),打开debugview
就可以在其中看到输出的调试信息。
DebugView 调试入门
3. _beginthreadex
待补充
二、总结
1、CreateThread,线程中不使用CRT,不使用MFC库
2、_beginthreadex,线程中使用CRT,不使用MFC库,初始化CRT后,调用CreateThread
3、AfxbeginThread,线程中使用CRT,使用MFC库,或者其中任何之一,初始化MFC后,调用_beginthreadex
MFC中线程创建的函数,首先创建了相应的CWinThread对象,然后调用CWinThread::CreateThread,在CWinThread::CreateThread中完成了对线程对象的初始化工作,然后,调用_beginthreadex创建线程。注意不要在一个MFC程序中使用_beginthreadex()或CreateThread()。
上一篇: C# 多线程使用委托修改界面UI
下一篇: 线程间通信