CreateThread函数为进程创建一个线程。必须给创建的线程声明一个开始地址,使这个线程可以从这个地址开始执行。一般的,这个地址就是程序里定义的一个函数的名字。这个函数有一个参数,一个DWORD类型的返回值。进程可以拥有运行同一函数的多个线程。
下面的例子说明怎么样创建一个新线程,这个线程执行一个本地定义的函数:ThreadProc。被建立的线程利用一块动态开辟的缓存,给每一个线程对应的函数传递唯一的信息(说白了,就是利用指针向线程函数传递参数)。线程函数负责释放内存。
主线程利用WaitForMultipleObjects函数来等待所有工作线程运行终止。需要注意的是,在工作线程终止之前关闭了它的句柄(HANDLE)不会终止工作线程的运行。但是,句柄会在之后的调用中不可用。
(程序注释是我加的)
#include <windows.h>
#include <strsafe.h>
#define MAX_THREADS 3
#define BUF_SIZE 255
typedef struct _MyData { //这个就是线程参数,可以自定义
int val1;
int val2;
} MYDATA, *PMYDATA;
DWORD WINAPI ThreadProc( LPVOID lpParam ) //线程函数必须定义成这个样子,
//形式参数是一个LPVOID指针
{
HANDLE hStdout;
PMYDATA pData;
TCHAR msgBuf[BUF_SIZE];
size_t cchStringSize;
DWORD dwChars;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
if( hStdout == INVALID_HANDLE_VALUE )
return 1;
// Cast the parameter to the correct data type.
pData = (PMYDATA)lpParam; //这里就是把参数强制转换成
//自定义的类型
// Print the parameter values using thread-safe functions.
StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %d "),
pData->val1, pData->val2);
StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);
WriteConsole(hStdout, msgBuf, cchStringSize, &dwChars, NULL);
// Free the memory allocated by the caller for the thread
// data structure.
HeapFree(GetProcessHeap(), 0, pData);
return 0;
}
void main()
{
PMYDATA pData;
DWORD dwThreadId[MAX_THREADS];
HANDLE hThread[MAX_THREADS];
int i;
// Create MAX_THREADS worker threads.
for( i=0; i<MAX_THREADS; i++ )
{
// Allocate memory for thread data.
pData = (PMYDATA) HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(MYDATA));
if( pData == NULL )
ExitProcess(2);
// Generate unique data for each thread.
pData->val1 = i;
pData->val2 = i+100;
hThread[i] = CreateThread( //创建线程的winapi函数
NULL, // default security attributes
0, // use default stack size
ThreadProc, // thread function
pData, // argument to thread function
0, // use default creation flags
&dwThreadId[i]); // returns the thread identifier
// Check the return value for success.
if (hThread[i] == NULL)
{
ExitProcess(i);
}
}
// Wait until all threads have terminated.
WaitForMultipleObjects(MAX_THREADS, hThread, TRUE, INFINITE);
// Close all thread handles upon completion.
for(i=0; i<MAX_THREADS; i++)
{
CloseHandle(hThread[i]);
}
}
ThreadProc函数没有使用C运行时库(CRT),因为如果不使用多线程CRT(multithreaded CRT),它的很多函数都不是线程安全的。如果想在ThreadProc中使用CRT,用_beginthreadex创建线程。
如果创建线程在新线程之前退出,那么传递一个本地变量的地址是危险的,因为指针将会无效。所以,传递一个动态开辟的内存,或者创建线程等待新线程终止都可以避免这个情况发生。也可以利用全局变量将参数从创建线程传递到新线程。如果利用全局变量,就很有必要做好互斥工作。查看《多线程同步》可以得到更多信息。
创建线程可以利用CreateThread重的几个参数声明新线程的几个特征:
1、新线程句柄的安全属性。这些安全属性包含一个继承标志,它们可以决定这个句柄能否被子进程继承。安全属性也包含一个安全描述符,有了这个描述符,在之后对线程句柄的所有操作之前,系统都要检查权限。(我:一般情况下直接传递NULL)
2、新线程的初始栈尺寸。线程的栈是在进程的内存空间中自动生成的;系统在需要的时候扩大栈的尺寸,在线程终止的时候回收栈。(我:一般情况下直接默认)
3、创建标志允许创建一个挂起的线程。创建这样的线程之后,调用ResumeThread函数环形线程。