什么是线程
1、在Windows平台上,最终可以利用CPU执行代码的最小尸体就是线程
2、首先从内核角度看,线程是一个内核对象,系统用它来村塾一些关于线程统计信息(比如时间)
3、从编程角度来看,线程是一堆寄存器状态以及线程栈的一个结构体对象,本质上可以理解为一个函数调用其(
寄存器状态用与控制CPU执行,栈用于存储局部变量和函数调用参数及函数返回地址)
4、最后需要知道的就是线程还可以带有几个队列(简单的理解为异步函数调用队列):
消息队列(GUI线程系统内部会创建)
APC队列(调用APC函数时会创建)
(注意:这些队列在线程创建时比并不存在)
5、线程就是执行体
什么时候不使用线程
1、当一个算法是严格穿行化的时候,也就是计算的每一步都严重以来前一个操作步骤的结果的时候
2、当有多个功能任务也具有比较严格的先后逻辑关系的时候,不宜采用多线程
3、还有一个特殊情况,比如一个服务器需要处理成千上万个客户端链接,并处理不同的请求的时候,这种
情况下应当优先考虑线程池,而不是简单的多线程。
默认的线程函数必须具有如下原型
DWORD WINAPI ThreadProc(LPVOID LpParameter);
调用API:CreateThread可以创建一个新进程
HANDLE WINAPI CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
dwStackSize用于指定线程初始时的栈大小,通常传入0即可,此时系统会使用一个合适的大小
lpStartAddress就是新进程入口函数的地址
lpParameter就是传入线程入口的参数,这个参数完全由调用者使用,系统只是简单的将这个参数
传递给线程函数,并不做别的任何处理
dwCreationFlags指出创建线程的方式,如果是0,表示线程一被创建就被立即执行,如果是CREATE_SUSPENDED,
表示线程一被创建先暂停,并不执行,在XP以上的系统中此参数还可以结合一个STACK_SIZE_PARAM_IS_A_RESERVATION
用于指出设置dwStackSize起始只是为线程栈保留的虚拟地址空间的大小,并不需要实际提交那么多的物理页面
如果没有指定这个标志位,那么dwStackSize也是实际提交内存的大小值
lpThreadId则用于得到线程唯一的标识符
1、参数的结果是随机的,表明CPU调用线程完全是随机的
2、这充分说明Windows线程调度机制的最终行为是随机的,是一个抢占式多任务的系统
3、因此分析多线程程序的时候,一般不能假设某个线程会被先调度,某个线程会被后调度,也即
不能假设线程执行的顺序这样的行为
4、虽然windows调度程序时间是按分时多任务方式来轮流调度线程的,而且这个时间片是20ms,
但是从宏观的角度来看,比如1秒的时间粒度,这些线程可以被认为是“同时”运行的
5、这些信息说明,无论线程调度如何执行,在分析时始终认为这些线程实际上时并行执行的,
这样就可以把繁琐的分析简单化
6、下面的例子只是用了一个线程函数,而这个函数起始访问了一个公共资源STDOUTPUT
7、在windows系统中,大多数内核对象的操作室严格穿行化的,因此无论线程如何并发的执行,
最终输出的结果都是完整有序的,因为调用的WriteConsole方法本身是严格串行化的(否则输出是混乱的)
8、有时虽然线程本身是被认为是并发的,但在实际中又确实需要对他们执行的顺序进行一些不要的控制和管理,
这是就需要进行多线程并发控制
#include
#include
#include
#include
#define GRS_ALLOC(sz) HeapAlloc(GetProcessHeap(),0,sz)
#define GRS_CALLOC(sz) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz)
#define GRS_SAFEFREE(p) if(NULL!=p){HeapFree(GetProcessHeap(),0,p);p=NULL;}
#define GRS_USEPRINTF() TCHAR pBuf[1024]={}
#define GRS_PRINTF(...)\
StringCchPrintf(pBuf, 1024, __VA_ARGS__); \
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), pBuf, lstrlen(pBuf), NULL, NULL);
#define MAX_THREADS 10 //最大线程数
DWORD WINAPI MyThreadFunction(LPVOID lpParam);
void ErrorHandler(LPTSTR lpszFunction);
//自定义线程数据
typedef struct MyData
{
int val1;
int val2;
}MYDATA, *PMYDATA;
int _tmain()
{
PMYDATA pDataArray[MAX_THREADS];
DWORD dwThreadIdArray[MAX_THREADS];
HANDLE hThreadArray[MAX_THREADS];
//创建线程循环
for (int i = 0; i < MAX_THREADS; i++)
{
pDataArray[i] = (PMYDATA)GRS_CALLOC(sizeof(MYDATA));
pDataArray[i]->val1 = i;
pDataArray[i]->val2 = i + 100;
hThreadArray[i] = CreateThread(NULL, 0, MyThreadFunction, pDataArray[i], 0, &dwThreadIdArray[i]);
if (hThreadArray[i] == NULL)
{
ErrorHandler(_T("CreateThread"));
ExitProcess(3);
}
}
WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);
for (int i = 0; i < MAX_THREADS; i++)
{
CloseHandle(hThreadArray[i]);
GRS_SAFEFREE(pDataArray[i]);
}
_tsystem(_T("PAUSE"));
return 0;
}
DWORD WINAPI MyThreadFunction(LPVOID lpParam)
{
//线程函数
GRS_USEPRINTF();
PMYDATA pDataArray = (PMYDATA)lpParam;
GRS_PRINTF(_T("Parameters=%d,%d\n"),pDataArray->val1,pDataArray->val2);
return 0;
}
void ErrorHandler(LPTSTR lpszFunction)
{
GRS_USEPRINTF();
LPVOID lpMsgBuf;
DWORD dw = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
0,NULL
);
GRS_PRINTF(_T("%s failed with error %d:%s"),lpszFunction,dw,lpMsgBuf);
LocalFree(lpMsgBuf);
}