vc++socket笔记2-1
我也不知道为什么这本书突然教起了多线程,但是多学点也不亏。
进程是一个正在执行的程序,一个进程可以开辟多个线程,每个线程在操作系统中会有一个线程对象,这块内存是操作系统管理,在windows操作系统中可以用windows的api来处理线程对象。
开辟出一个线程后这块线程的动作由我们自己写的函数决定,在这个函数里尽量不要用CRT库的函数,因为windows操作系统不会对这类库的函数进行内存处理。
CRT库是C运行时库(C Run-Time Library),没有这个库main()就不会被调用,exit()也不会被响应。
示例1:
#include<Windows.h> #include<strsafe.h>// 缓冲区处理 #define MAX_THREADS 500 #define BUF_SIZE 255 typedef struct _MyData //我的数据类,包含两个int类型值 { int val1; int val2; }MYDATA, * PMYDATA; DWORD WINAPI ThreadProc(LPVOID lpParam)// LPVOID 是 void* 的意思 { HANDLE hStdout; PMYDATA pData; TCHAR msgBuf[BUF_SIZE]; // TCHAR 是 WCHAR 的别名,是宽字符的意思,也就是两字节的字符类型,类似汉字 size_t cchStringSize; DWORD dwChars; hStdout = GetStdHandle(STD_OUTPUT_HANDLE); //得到标准输出设备的句柄,用于打印 if (hStdout == INVALID_HANDLE_VALUE)return 1; pData = (PMYDATA)lpParam; // 将void*类型的参数强转为MYDATA*的类型 // 双引号前加L表示是宽字符 StringCchPrintf(msgBuf, BUF_SIZE, L"Parameter=%d,%d\n", pData->val1, pData->val2);// 代替sprintf StringCchLength(msgBuf, BUF_SIZE, &cchStringSize); // 代替strlen WriteConsole(hStdout, msgBuf, cchStringSize, &dwChars, NULL);// 代替printf HeapFree(GetProcessHeap(), 0, pData);// 释放内存 return 0; } int main(int argc, TCHAR* argv[]) { PMYDATA pData; DWORD dwThreadId[MAX_THREADS]; HANDLE hThread[MAX_THREADS]; int i; printf("----------------begin-----------------\n"); for (i = 0;i < MAX_THREADS;i++) { pData = (PMYDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MYDATA));// 申请内存 if (pData == NULL) ExitProcess(2); pData->val1 = i; pData->val2 = i; hThread[i] = CreateThread(NULL, 0, ThreadProc, pData, 0, &dwThreadId[i]);// 创建线程,在这个函数中不要用CRT库函数,不然会内存泄漏 if (hThread[i] == NULL) ExitProcess(i); } for (i = 0;i < MAX_THREADS;i++) { WaitForSingleObject(hThread[i], INFINITE);// 等待第i个线程结束 CloseHandle(hThread[i]);// 关闭线程对象,释放系统资源 } printf("----------------end---------------\n"); return 0; }

哪怕是后面才开始的线程也可以在前面就已经开始的线程打印字符前打印字符,0,0就比499,499晚结束。
示例2:
#include<Windows.h> #include<strsafe.h>// 缓冲区处理 #define MAX_THREADS 100 #define BUF_SIZE 255 typedef struct _MyData //我的数据类,包含两个int类型值 { int val1; int val2; }MYDATA, * PMYDATA; int allTheSum = 0;// 给所有人算的数 double My_SQRT(double Num, int times)// 用迭代法开根号 { double last = 1; for (int i = 0;i < times;i++)last = (last + Num / last) / 2.0; return last; } DWORD WINAPI ThreadProc(LPVOID lpParam)// LPVOID 是 void* 的意思 { HANDLE hStdout; PMYDATA pData; TCHAR msgBuf[BUF_SIZE]; // TCHAR 是 WCHAR 的别名,是宽字符的意思,也就是两字节的字符类型,类似汉字 size_t cchStringSize; DWORD dwChars; hStdout = GetStdHandle(STD_OUTPUT_HANDLE); //得到标准输出设备的句柄,用于打印 if (hStdout == INVALID_HANDLE_VALUE)return 1; pData = (PMYDATA)lpParam; // 将void*类型的参数强转为MYDATA*的类型 // 双引号前加L表示是宽字符 switch (pData->val1 % 7)// 当前数据标记,谁先到谁先算 { case 0:allTheSum += 10;break; case 1:allTheSum -= 7;break; case 2:allTheSum *= 6;break; case 3:allTheSum /= 3;break; case 4:allTheSum = 2 * allTheSum + 1;break; case 5:allTheSum = (allTheSum + 1) * allTheSum / 2;break; case 6:allTheSum = My_SQRT(allTheSum, 10);break; default: break; } StringCchPrintf(msgBuf, BUF_SIZE, L"Parameter=%d,%d\n", pData->val1, allTheSum);// 代替sprintf StringCchLength(msgBuf, BUF_SIZE, &cchStringSize); // 代替strlen WriteConsole(hStdout, msgBuf, cchStringSize, &dwChars, NULL);// 代替printf HeapFree(GetProcessHeap(), 0, pData);// 释放内存 return 0; } int main(int argc, TCHAR* argv[]) { PMYDATA pData; DWORD dwThreadId[MAX_THREADS]; HANDLE hThread[MAX_THREADS]; int i; printf("----------------begin-----------------\n"); for (i = 0;i < MAX_THREADS;i++) { pData = (PMYDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MYDATA));// 申请内存 if (pData == NULL) ExitProcess(2); pData->val1 = i; pData->val2 = i; hThread[i] = CreateThread(NULL, 0, ThreadProc, pData, 0, &dwThreadId[i]);// 创建线程,在这个函数中不要用CRT库函数,不然会内存泄漏 if (hThread[i] == NULL) ExitProcess(i); } for (i = 0;i < MAX_THREADS;i++) { WaitForSingleObject(hThread[i], INFINITE);// 等待第i个线程结束 CloseHandle(hThread[i]);// 关闭线程对象,释放系统资源 } printf("AllTheSum=%d\n", allTheSum); printf("----------------end---------------\n"); getchar(); return 0; }


在研究这个代码时我发现有函数前面有WINAPI,一开始我以为它是返回值类型,但是看了定义才知道这是个调用约定。
__stdcall,__cdecl,__fastcall,thiscall都是调用约定。
__stdcall调用约定是Windows操作系统的调用约定,它在函数返回前清理函数参数的内存栈,占用内存较小。
__cdecl调用约定是C、C++程序缺省调用方式,也就是你不去写它就默认是这个,每一个调用它的函数都包含清空堆栈的代码,内存占用比较大。但是用到可变参数列表的函数始终是用__cdecl调用约定。
__fastcall调用约定将传入参数的最后两个4字节参数放进ECX,EDX寄存器中,调用参数比较快。
thiscall是C++的调用约定,将this指针放进CX寄存器,由于thiscall不是关键词,所以这个调用约定不能被程序员用。
不过为了干翻微软,__stdcall我还是尽量少用。
浙公网安备 33010602011771号