HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD描述施行与这一新线程的security属性,NULL表示使用缺省值,在windows 95中忽略该参数 DWORD dwStackSize, // initial stack size新线程拥有的堆栈大小,0表示缺省大小,1MB LPTHREAD_START_ROUTINE lpStartAddress, // thread function 函数指针 LPVOID lpParameter, // thread argument 传递到线程函数的参数 DWORD dwCreationFlags, // creation option 允许产生一个暂时挂起的线程,默认为立即运行 LPDWORD lpThreadId // thread identifier //新的线程ID会被传回到这里 );
#define WIN32_LEAN_AND_MEAN #include<stdio.h> #include<stdlib.h> #include<windows.h> DWORD WINAPI ThreadFunc(LPVOID); //线程标准函数形式 //#define WINAPI _stdcall int main() { HANDLE hThrd; DWORD threadId; int i; for(i=0;i<5;i++) { hThrd=CreateThread(NULL,0,ThreadFunc,(LPVOID)i,0,&threadId); //返回一个核心对象hThrd if(hThrd) { printf("Thread Start %d\n",i); CloseHandle(hThrd); } } Sleep(2000); //等待这些线程完成,不加这句,主线程将结束,其他线程将无法完成 return EXIT_SUCCESS; } DWORD WINAPI ThreadFunc(LPVOID n) { int i; for(i=0;i<10;i++) { printf("%d%d%d%d%d%d%d%d\n",n,n,n,n,n,n,n,n); } return 0; }
BOOL CloseHandle( HANDLE hObject // handle to object );
BOOL GetExitCodeThread( HANDLE hThread, // handle to the thread LPDWORD lpExitCode // termination status );
#define WIN32_LEAN_AND_MEAN #include<stdio.h> #include<stdlib.h> #include<windows.h> #include<conio.h> DWORD WINAPI ThreadFunc(LPVOID); //线程标准函数形式 int main() { HANDLE hThrd1; HANDLE hThrd2; DWORD exitCode1=0; DWORD exitCode2=0; DWORD threadId; hThrd1=CreateThread(NULL,0,ThreadFunc,(LPVOID)1,0,&threadId); if(hThrd1) printf("Thread 1 launched \n"); hThrd2=CreateThread(NULL,0,ThreadFunc,(LPVOID)2,0,&threadId); if(hThrd2) printf("Thread 2 launched \n"); for(;;) { printf("Press any key to exit..\n"); getch(); //GetExitCodeThread等待一个线程的结束,但这并不是最好的方法 GetExitCodeThread(hThrd1,&exitCode1); //GetExitCodeThread将传回线程函数ThreadFunc的返回值 GetExitCodeThread(hThrd2,&exitCode2); if(exitCode1==STILL_ACTIVE) puts("Thread 1 is still running ..."); if(exitCode2==STILL_ACTIVE) puts("Thread 2 is still running ..."); if(exitCode1!=STILL_ACTIVE&&exitCode2!=STILL_ACTIVE) break; } CloseHandle(hThrd1); CloseHandle(hThrd2); printf("Thread 1 returned %d\n",exitCode1); printf("Thread 2 returned %d\n",exitCode2); return EXIT_SUCCESS; } DWORD WINAPI ThreadFunc(LPVOID n) { Sleep((DWORD)n*1000*2); return (DWORD)n*2; }
VOID ExitThread( DWORD dwExitCode // exit code for this thread 指示此线程之结束代码 );
#define WIN32_LEAN_AND_MEAN #include<stdio.h> #include<stdlib.h> #include<windows.h> DWORD WINAPI ThreadFunc(LPVOID); //线程标准函数形式 void AnotherFunc(void); int main() { HANDLE hThrd; DWORD exitCode=0; DWORD threadId; hThrd=CreateThread(NULL,0,ThreadFunc,(LPVOID)1,0,&threadId); if(hThrd) printf("Thread launched.. \n"); for(;;) { bool rc; rc=GetExitCodeThread(hThrd,&exitCode); if(rc&&exitCode!=STILL_ACTIVE) break; } CloseHandle(hThrd); printf("Thread returned %d\n",exitCode); return EXIT_SUCCESS; } DWORD WINAPI ThreadFunc(LPVOID n) { printf("Thread running ..\n"); AnotherFunc(); //调用一个函数,退出该线程 return 0; } void AnotherFunc() { printf("About to exit Thread ..\n"); ExitThread(4); printf("This will never print ..\n"); //这一行不会被打印 }
//示例错误处理
#define WIN32_LEAN_AND_MEAN
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
//////////////////MTVERIFY宏进入////////////
#include "MtVerify.h"
DWORD WINAPI ThreadFunc(LPVOID);
int main()
{
HANDLE hThrd;
DWORD exitCode=0;
DWORD threadId;
MTVERIFY(hThrd=CreateThread(NULL,0,ThreadFunc,(LPVOID)1,0,&threadId));
if(hThrd)
printf("Thread launched.. \n");
MTVERIFY(CloseHandle(hThrd));
for(;;)
{
bool rc;
MTVERIFY(rc=GetExitCodeThread(hThrd,&exitCode));
if(rc&&exitCode!=STILL_ACTIVE)
break;
}
printf("Thread returned %d\n",exitCode);
return EXIT_SUCCESS;
}
DWORD WINAPI ThreadFunc(LPVOID n)
{
printf("Thread running ..\n");
return 0;
}
/**
* MtVerify.h
*
* Error handling for applications in
* "Multitheading Applications in Win32"
*
* The function PrintError() is marked as __inline so that it can be
* included from one or more C or C++ files without multiple definition
* errors. For the examples in this book, this works fine.
* To use the PrintError() in an application, it should be taken out,
* placed in its own source file, and the "__inline" declaration removed
* so the function will be globally available.
*/
#pragma comment( lib, "USER32" )
#include <stdlib.h>
#include <crtdbg.h>
#define MTASSERT(a) _ASSERTE(a)
// 宏定义 __FILE__ 与__LINE__都是预处理符号提供错误信息的描述
// 如果a返回FALSE就执行PrintError函数
#define MTVERIFY(a) if (!(a)) PrintError(#a,__FILE__,__LINE__,GetLastError())
__inline void PrintError(LPSTR linedesc, LPSTR filename, int lineno, DWORD errnum)
{
LPSTR lpBuffer;
char errbuf[256];
#ifdef _WINDOWS
char modulename[MAX_PATH];
#else // _WINDOWS
DWORD numread;
#endif // _WINDOWS
// 把从GetLastError()返回的错误码转化为错误信息
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
errnum,
LANG_NEUTRAL,
(LPTSTR)&lpBuffer,
0,
NULL );
wsprintfA(errbuf, "\nThe following call failed at line %d in %s:\n\n"
" %s\n\nReason: %s\n", lineno, filename, linedesc, lpBuffer);
// 如果是console程序就输出信息到控制台上
#ifndef _WINDOWS
WriteFile(GetStdHandle(STD_ERROR_HANDLE), errbuf, strlen(errbuf), &numread, FALSE );
// 等待3秒钟是为了使用者看到出错信息
Sleep(3000);
// 如果是窗口程序就一弹出对话框的形式输出错误信息
#else
// 当前exe文件的全路径
GetModuleFileName(NULL, modulename, MAX_PATH);
// 置弹出窗口在最上层以免被忽略
MessageBox(NULL, errbuf, modulename, MB_ICONWARNING|MB_OK|MB_TASKMODAL|MB_SETFOREGROUND);
#endif
// 把结束代码EXIT_FAILURE 交给操作系统
exit(EXIT_FAILURE);
}
多线程综合实例:后台打印,建立一个Win32 Application
/*多线程后台打印范例*/ /******************************/ /* * * * Sample code for "Multithreading Applications in Win32" * This is from Chapter 2, Listing 2-3 * * Demonstrates background printing */ #define WIN32_LEAN_AND_MEAN #include <stdio.h> #include <stdlib.h> #include <windows.h> #include <windowsx.h> #include <commdlg.h> #include "resource.h" #include "MtVerify.h" // // Macro definitions // #define WM_SHOWBITMAP WM_APP #define MAX_PRINT_JOBS 64 // // Structures // typedef struct { // Information passed to background thread for printing HWND hDlg; HWND hWndParent; HDC hDc; BOOL bPrint; // TRUE if printing; char szText[256]; } ThreadPrintInfo; // // Global variables // HANDLE hInst; HBITMAP gbmpDisplay; RECT gDisplayRect; int gNumPrinting = 0; // Handle to each created thread HANDLE gPrintJobs[64]; //保存已经创建的线程 // Height of bitmap returned by DrawText int iHeight; // HWND of the dialog so other threads can find it. HWND hDlgMain; // // Function declarations // int APIENTRY WinMain(HINSTANCE hInstance/*当前程序运行实例的句柄,每个程序可以运行多个实例*/, HINSTANCE hPrevInstance, /*当前实例前一个实例的句柄 ,win32下为NULL*/ LPSTR lpCmdLine, /*指定传递给命令行的参数*/ int nCmdShow/*指定程序窗口应该如何显示,如最大化等*/); LRESULT CALLBACK MainWndProc(HWND hWnd/*标志接受消息的具体窗口*/, unsigned msg, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK PrintDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); BOOL PrintDlg_OnInitDialog(HWND hwndDlg, HWND hwndFocus, LPARAM lParam); void PrintDlg_OnCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify); void PrintDlg_OnPaint(HWND hwnd); void PrintText(HWND hwndParent, char *pszText); void PrintToDisplay(HWND hwndParent, char *pszText); LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); DWORD WINAPI BackgroundPrintThread(LPVOID pVoid); /////////////////////////////////////////////////////////// // // WinMain // // Main entry point of application. This will be a // dialog based app, not a normal window, so this // routine acts a little differently than "normal". // int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; HWND hWnd; WNDCLASS wc; int index; hInst = hInstance; //1.设计一个窗口类 if (!hPrevInstance) { memset(&wc, 0, sizeof(wc)); wc.lpfnWndProc = MainWndProc; wc.hInstance = hInstance; wc.hIcon = LoadIcon (hInstance, "GenIco"); wc.hCursor = LoadCursor(NULL,IDC_ARROW); wc.hbrBackground= GetSysColorBrush(COLOR_BACKGROUND); wc.lpszMenuName = "PRINTING_MENU"; wc.lpszClassName= "PrintDlgClass"; if (!RegisterClass(&wc)) return FALSE; } //2.创建窗口,并返回创建成功后的窗口句柄 hWnd = CreateWindow( "PrintDlgClass", "Background Printing", WS_OVERLAPPED|WS_CAPTION|WS_MINIMIZEBOX|WS_SYSMENU, CW_USEDEFAULT, // At this point we do not want to 0, // show the window until we know 0, // how big the Dialog Box is so 0, // that we can fit the main window NULL, // around it. NULL, hInstance, NULL); //创建打印对话框 hDlgMain = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PRINT), hWnd, PrintDlgProc); //3.显示及刷新窗口 ShowWindow(hWnd, nCmdShow); ShowWindow(hDlgMain, SW_SHOW); //4.消息循环 while (GetMessage(&msg, NULL, 0, 0)) { // Get Next message in queue if(hDlgMain == NULL || !IsDialogMessage(hDlgMain,&msg)) { TranslateMessage(&msg); /* Translate virtual key codes */ DispatchMessage(&msg); /* Dispatches message to window */ } } // end while // Wait for all threads to terminate. The Window will // have already disappeared by this point. //等待各个线程结束 for (index = 0; index < gNumPrinting; index++) { DWORD status; do { // Wait for thread to terminate GetExitCodeThread(gPrintJobs[index], &status); Sleep(10); } while (status == STILL_ACTIVE); } // end for return (msg.wParam); /* Returns the value from PostQuitMessage */ } //主窗口回调函数 LRESULT CALLBACK MainWndProc(HWND hWnd, unsigned msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CREATE: break; case WM_COMMAND: switch (wParam) { case IDM_ABOUT: DialogBox(hInst, "AboutBox", hWnd, (DLGPROC)About); break; case IDM_EXIT: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wParam, lParam)); } case WM_SETFOCUS: // ensure that the Dialog Box has the focus SetFocus(hDlgMain); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, msg, wParam, lParam); } return 0; } LRESULT CALLBACK PrintDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CLOSE: DestroyWindow(hDlg); hDlgMain = NULL; break; case WM_DESTROY: return TRUE; break; case WM_SHOWBITMAP: if (gbmpDisplay) DeleteObject(gbmpDisplay); gDisplayRect = *(RECT*)wParam; gbmpDisplay = (HBITMAP) lParam; InvalidateRect(hDlgMain, NULL, TRUE); break; HANDLE_MSG(hDlg, WM_INITDIALOG, PrintDlg_OnInitDialog); HANDLE_MSG(hDlg, WM_COMMAND, PrintDlg_OnCommand); HANDLE_MSG(hDlg, WM_PAINT, PrintDlg_OnPaint); default: return (FALSE); } return 0; } BOOL PrintDlg_OnInitDialog(HWND hwndDlg, HWND hwndFocus, LPARAM lParam) { RECT rect; // Size parent to fit this dialog GetWindowRect(hwndDlg, &rect); SetWindowPos(GetParent(hwndDlg),NULL, 0,0, rect.right-rect.left, rect.bottom-rect.top+GetSystemMetrics(SM_CYMENU) +GetSystemMetrics(SM_CYCAPTION), SWP_NOMOVE | SWP_NOZORDER); return TRUE; } void PrintDlg_OnCommand(HWND hDlg, int id,HWND hwndCtl, UINT codeNotify) { char szText[256]; switch (id) { case IDC_PRINT: GetDlgItemText(hDlg, IDC_EDIT_TEXT, szText, 256); PrintText(hDlg, szText); break; case IDC_DISPLAY: GetDlgItemText(hDlg, IDC_EDIT_TEXT, szText, 256); PrintToDisplay(hDlg, szText); break; case IDCANCEL: case IDM_EXIT: PostMessage(GetParent(hDlg),WM_DESTROY, (WPARAM)0, (LPARAM)0); DestroyWindow(hDlgMain); hDlgMain = NULL; break; default: break; } } void PrintDlg_OnPaint( HWND hwnd ) { PAINTSTRUCT paint; HWND hwndCtrl; HDC hdc; HDC hDcMem; HBITMAP bmpOld; RECT rect; POINT point; if (!gbmpDisplay) return; hwndCtrl = GetDlgItem(hwnd, IDC_OUTPUT); hdc = BeginPaint(hwnd, &paint); GetWindowRect(hwndCtrl, &rect); point = *((POINT *)&rect); ScreenToClient(hwnd, &point); hDcMem = CreateCompatibleDC(NULL); bmpOld = SelectObject(hDcMem, gbmpDisplay); // Copy bitmap to screen MTVERIFY( BitBlt(hdc, point.x+10, point.y+40, gDisplayRect.right-gDisplayRect.left, gDisplayRect.bottom-gDisplayRect.top, hDcMem, iHeight, 0, SRCCOPY) ); SelectObject(hDcMem, bmpOld); DeleteDC(hDcMem); EndPaint(hwnd, &paint); } // // Asks user which printer to use, then creates // background printing thread. // void PrintText(HWND hwndParent, char *pszText) { ThreadPrintInfo *pInfo; HANDLE hThread; DWORD dwThreadId; int result; DOCINFO docInfo; PRINTDLG dlgPrint; // Put up Common Dialog for Printing and get hDC. memset(&dlgPrint, 0, sizeof(PRINTDLG)); dlgPrint.lStructSize = sizeof(PRINTDLG); dlgPrint.hwndOwner = hwndParent; dlgPrint.Flags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_RETURNDC; dlgPrint.hInstance = hInst; if (!PrintDlg(&dlgPrint)) return; // Initialize Printer device docInfo.cbSize = sizeof(DOCINFO); docInfo.lpszDocName = "Background Printing Example"; docInfo.lpszOutput = NULL; docInfo.lpszDatatype = NULL; docInfo.fwType = 0; result = StartDoc(dlgPrint.hDC, &docInfo); result = StartPage(dlgPrint.hDC); pInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ThreadPrintInfo)); pInfo->hDlg = hwndParent; pInfo->hWndParent = hwndParent; pInfo->hDc = dlgPrint.hDC; pInfo->bPrint = TRUE; strcpy(pInfo->szText, pszText); MTVERIFY( hThread = CreateThread(NULL, 0, BackgroundPrintThread, (LPVOID)pInfo, 0, &dwThreadId )); // keep track of all background printing threads gPrintJobs[gNumPrinting++] = hThread; } // // Shows output on the dialog box. // void PrintToDisplay(HWND hwndParent, char *pszText) { ThreadPrintInfo *pInfo; DWORD dwThreadId; HANDLE hThread; pInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ThreadPrintInfo)); pInfo->hDlg = hwndParent; pInfo->hWndParent = GetDlgItem(hwndParent, IDC_OUTPUT); pInfo->hDc = GetDC(pInfo->hWndParent); pInfo->bPrint = FALSE; strcpy(pInfo->szText, pszText); MTVERIFY( hThread = CreateThread(NULL, 0, BackgroundPrintThread, (LPVOID)pInfo, 0, &dwThreadId )); // keep track of all background printing threads gPrintJobs[gNumPrinting++] = hThread; } //--------------------------------------------------------- // About Box Handling //--------------------------------------------------------- LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, TRUE); return (TRUE); } break; default: return (DefWindowProc(hDlg, message, wParam, lParam)); } return FALSE; } //--------------------------------------------------------- // Background Printing Code后台线程打印函数 //--------------------------------------------------------- DWORD WINAPI BackgroundPrintThread(LPVOID pVoid) { ThreadPrintInfo *pInfo = (ThreadPrintInfo*) pVoid; RECT rect; RECT rectMem; HDC hDcMem; HBITMAP bmpMem; HBITMAP bmpOld; int x, y; int counter = 0; int nHeight; HFONT hFont; HFONT hFontOld; // Get dimensions of paper into rect rect.left = 0; rect.top = 0; rect.right = GetDeviceCaps(pInfo->hDc, HORZRES); rect.bottom = GetDeviceCaps(pInfo->hDc, VERTRES); nHeight = -MulDiv(36, GetDeviceCaps(pInfo->hDc, LOGPIXELSY), 72); // Create Font hFont = CreateFont(nHeight, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH, NULL); MTASSERT( hFont != 0); // Draw into memory device context hDcMem = CreateCompatibleDC(pInfo->hDc); hFontOld = SelectObject(hDcMem, hFont); iHeight = DrawText(hDcMem, pInfo->szText, -1, &rect, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT); rectMem = rect; rectMem.left = rect.left + iHeight; rectMem.right = rect.right + (iHeight*2); bmpMem = CreateCompatibleBitmap(hDcMem, rectMem.right, rect.bottom); bmpOld = SelectObject(hDcMem, bmpMem); OffsetRect(&rect, iHeight, 0); DrawText(hDcMem, pInfo->szText, -1, &rect, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK); // Italicize bitmap. We use GetPixel and // SetPixel because they are horribly inefficient, // thereby causing the thread to run for awhile. for (y = 0; y < iHeight; y++) { // Italicize line y for (x = rectMem.right; x > iHeight; x--) { // Move specified pixel to the right. COLORREF color; int offset; offset = y - iHeight; color = GetPixel(hDcMem, x + offset, y); if (color != 0) counter++; SetPixel(hDcMem, x, y, color); } // end for x } // end for y MTASSERT( counter > 0); // Copy bitmap of italicized text from memory to device if (pInfo->bPrint) { BitBlt(pInfo->hDc, 50, 50, rectMem.right-rect.left, rectMem.bottom-rect.top, hDcMem, iHeight, 0, SRCCOPY); } SelectObject(hDcMem, hFontOld); SelectObject(hDcMem, bmpOld); DeleteDC(hDcMem); if (!pInfo->bPrint) { // We can't just write to the global variable where the // bitmap is kept or we might overwrite the work of // another thread, thereby "losing" a bitmap // Also, if we used PostMessage instead of SendMessage, then // the rectangle could have been deleted (it's on the stack) // by the time the main message loop is reached. SendMessage(pInfo->hDlg, WM_SHOWBITMAP, (WPARAM)&rectMem, (LPARAM) bmpMem); } if (pInfo->bPrint) { // Finish printing int result; result = EndPage(pInfo->hDc); MTASSERT (result != SP_ERROR); result = EndDoc(pInfo->hDc); MTASSERT (result != SP_ERROR); DeleteDC(pInfo->hDc); // If we are printing, we are done with the bitmap. DeleteObject(bmpMem); } else { ReleaseDC(pInfo->hWndParent, pInfo->hDc); } // free data structure passed in. HeapFree(GetProcessHeap(), 0, pInfo); return 0; }