【20090916】C++培训日记-多线程
= = 老师讲了创建多线程、利用互斥信号、利用事件对象、利用临界区和杀死线程的方法。以下是demo……
【多线程样例】
////////////////////////////////////////////////////////////////////////// // CopyRight(c) 2009, YOYO, All Rights Reserved. // Author: LIN YiQian // Created: 2009/09/16 // Describe: 多线程样例 ////////////////////////////////////////////////////////////////////////// #include <Windows.h> #include <iostream> using namespace std; DWORD WINAPI ThreadFun(LPVOID lpParameter); void main(void) { HANDLE hThread1 = CreateThread(NULL, 0, ThreadFun, new int(1), 0, NULL); HANDLE hThread2 = CreateThread(NULL, 0, ThreadFun, new int(2), 0, NULL); HANDLE hThread3 = CreateThread(NULL, 0, ThreadFun, new int(3), 0, NULL); CloseHandle(hThread1); CloseHandle(hThread2); CloseHandle(hThread3); Sleep(3000); return; } DWORD WINAPI ThreadFun(LPVOID lpParameter) { while (true) { printf("Thread %d is running..\n", *((int*)lpParameter)); Sleep(50); } }
【多线程:出现同步问题样例】
////////////////////////////////////////////////////////////////////////// // CopyRight(c) 2009, YOYO, All Rights Reserved. // Author: LIN YiQian // Created: 2009/09/16 // Describe: 多线程出错样例 演示 ////////////////////////////////////////////////////////////////////////// #include <Windows.h> #include <iostream> using namespace std; DWORD WINAPI SellTickets(LPVOID lpParameter); int g_nTicket = 100; void main(void) { HANDLE hThread1 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL); HANDLE hThread2 = CreateThread(NULL, 0, SellTickets, new int(2), 0, NULL); CloseHandle(hThread1); CloseHandle(hThread2); Sleep(3000); system("pause"); return; } DWORD WINAPI SellTickets(LPVOID lpParameter) { while (g_nTicket > 0) { printf("Thread %d sells ticket: No.%d\n", *((int*)lpParameter), g_nTicket--); } return NULL; }
【使用互斥信号量:线程结束时会自动释放占用的信号量】
////////////////////////////////////////////////////////////////////////// // CopyRight(c) 2009, YOYO, All Rights Reserved. // Author: LIN YiQian // Created: 2009/09/16 // Describe: 线程结束时会自动释放互斥量 演示 ////////////////////////////////////////////////////////////////////////// #include <Windows.h> #include <iostream> using namespace std; DWORD WINAPI ThreadFun(LPVOID lpParameter); HANDLE g_hMutex; void main(void) { g_hMutex = CreateMutex(NULL, FALSE, NULL); HANDLE hThread1 = CreateThread(NULL, 0, ThreadFun, new int(1), 0, NULL); HANDLE hThread2 = CreateThread(NULL, 0, ThreadFun, new int(2), 0, NULL); HANDLE hThread3 = CreateThread(NULL, 0, ThreadFun, new int(3), 0, NULL); CloseHandle(hThread1); CloseHandle(hThread2); CloseHandle(hThread3); CloseHandle(g_hMutex); system("pause"); } DWORD WINAPI ThreadFun(LPVOID lpParameter) { WaitForSingleObject(g_hMutex, INFINITE); printf("Thread %d is running..\n", *((int*)lpParameter)); return NULL; }
【使用互斥信号量解决同步问题(手动申请与释放互斥量)】
////////////////////////////////////////////////////////////////////////// // CopyRight(c) 2009, YOYO, All Rights Reserved. // Author: LIN YiQian // Created: 2009/09/16 // Describe: 线程手动申请释放互斥量 演示 ////////////////////////////////////////////////////////////////////////// #include <Windows.h> #include <iostream> using namespace std; DWORD WINAPI SellTickets(LPVOID lpParameter); int g_nTickets = 100; HANDLE g_hMutex; void main(void) { g_hMutex = CreateMutex(NULL, FALSE, NULL); HANDLE hThread1 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL); HANDLE hThread2 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL); HANDLE hThread3 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL); CloseHandle(hThread1); CloseHandle(hThread2); CloseHandle(hThread3); Sleep(1000); CloseHandle(g_hMutex); system("pause"); return; } DWORD WINAPI SellTickets(LPVOID lpParameter) { while (true) { WaitForSingleObject(g_hMutex, INFINITE); if (g_nTickets > 0) { printf("Thread %d sells ticket: No.%d\n", *((int*)lpParameter), g_nTickets--); } else { break; } ReleaseMutex(g_hMutex); } return NULL; }
【使用事件对象:手动重置事件对象(仍然有出现同步问题的可能)】
////////////////////////////////////////////////////////////////////////// // CopyRight(c) 2009, YOYO, All Rights Reserved. // Author: LIN YiQian // Created: 2009/09/16 // Describe: 手动重置事件对象 ////////////////////////////////////////////////////////////////////////// #include <Windows.h> #include <iostream> using namespace std; DWORD WINAPI SellTickets(LPVOID lpParameter); int g_nTickets = 100; HANDLE g_hEvent; void main(void) { g_hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); HANDLE hThread1 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL); HANDLE hThread2 = CreateThread(NULL, 0, SellTickets, new int(2), 0, NULL); HANDLE hThread3 = CreateThread(NULL, 0, SellTickets, new int(3), 0, NULL); CloseHandle(hThread1); CloseHandle(hThread2); CloseHandle(hThread3); CloseHandle(g_hEvent); system("pause"); return; } DWORD WINAPI SellTickets(LPVOID lpParameter) { while (true) { WaitForSingleObject(g_hEvent, INFINITE); ResetEvent(g_hEvent); if (g_nTickets > 0) { printf("Thread %d sells tickets: %d\n", *((int*) lpParameter), g_nTickets--); } else { break; } SetEvent(g_hEvent); } return NULL; }
【使用事件对象:自动重置】
////////////////////////////////////////////////////////////////////////// // CopyRight(c) 2009, YOYO, All Rights Reserved. // Author: LIN YiQian // Created: 2009/09/16 // Describe: 自动重置事件对象 演示 ////////////////////////////////////////////////////////////////////////// #include <Windows.h> #include <iostream> using namespace std; DWORD WINAPI SellTickets(LPVOID lpParameter); int g_nTickets = 100; HANDLE g_hEvent; void main(void) { g_hEvent = CreateEvent(NULL, FALSE, TRUE, NULL); HANDLE hThread1 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL); HANDLE hThread2 = CreateThread(NULL, 0, SellTickets, new int(2), 0, NULL); HANDLE hThread3 = CreateThread(NULL, 0, SellTickets, new int(3), 0, NULL); CloseHandle(hThread1); CloseHandle(hThread2); CloseHandle(hThread3); Sleep(1000); CloseHandle(g_hEvent); system("pause"); return; } DWORD WINAPI SellTickets(LPVOID lpParameter) { while (true) { WaitForSingleObject(g_hEvent, INFINITE); if (g_nTickets > 0) { printf("Thread %d sells ticket: No.%d\n", *((int*) lpParameter), g_nTickets--); } else { break; } SetEvent(g_hEvent); } return NULL; }
【使用临界区】
////////////////////////////////////////////////////////////////////////// // CopyRight(c) 2009, YOYO, All Rights Reserved. // Author: LIN YiQian // Created: 2009/09/16 // Describe: 使用临界区实现同步 演示 ////////////////////////////////////////////////////////////////////////// #include <Windows.h> #include <iostream> using namespace std; DWORD WINAPI SellTickets(LPVOID lpParameter); int g_nTickets = 100; CRITICAL_SECTION g_cs; void main(void) { InitializeCriticalSection(&g_cs); HANDLE hThread1 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL); HANDLE hThread2 = CreateThread(NULL, 0, SellTickets, new int(2), 0, NULL); HANDLE hThread3 = CreateThread(NULL, 0, SellTickets, new int(3), 0, NULL); CloseHandle(hThread1); CloseHandle(hThread2); CloseHandle(hThread3); Sleep(1000); DeleteCriticalSection(&g_cs); system("pause"); return; } DWORD WINAPI SellTickets(LPVOID lpParameter) { while (true) { EnterCriticalSection(&g_cs); if (g_nTickets > 0) { printf("Thread %d sells ticket: No.%d\n", *((int*)lpParameter), g_nTickets--); } else { break; } LeaveCriticalSection(&g_cs); } return NULL; }
【使用临界区:死锁样例】
////////////////////////////////////////////////////////////////////////// // CopyRight(c) 2009, YOYO, All Rights Reserved. // Author: LIN YiQian // Created: 2009/09/16 // Describe: 使用临界区造成死锁样例 ////////////////////////////////////////////////////////////////////////// #include <Windows.h> #include <iostream> using namespace std; DWORD WINAPI ThreadFun1(LPVOID lpParameter); DWORD WINAPI ThreadFun2(LPVOID lpParameter); CRITICAL_SECTION g_csA; CRITICAL_SECTION g_csB; void main(void) { InitializeCriticalSection(&g_csA); InitializeCriticalSection(&g_csB); HANDLE hThread1 = CreateThread(NULL, 0, ThreadFun1, NULL, 0, NULL); HANDLE hThread2 = CreateThread(NULL, 0, ThreadFun2, NULL, 0, NULL); CloseHandle(hThread1); CloseHandle(hThread2); Sleep(3000); DeleteCriticalSection(&g_csA); DeleteCriticalSection(&g_csB); system("pause"); return; } DWORD WINAPI ThreadFun1(LPVOID lpParameter) { while (true) { EnterCriticalSection(&g_csA); EnterCriticalSection(&g_csB); printf("Thread1 is running..\n"); LeaveCriticalSection(&g_csB); LeaveCriticalSection(&g_csA); } return NULL; } DWORD WINAPI ThreadFun2(LPVOID lpParameter) { while (true) { EnterCriticalSection(&g_csB); EnterCriticalSection(&g_csA); printf("Thread2 is running..\n"); LeaveCriticalSection(&g_csA); LeaveCriticalSection(&g_csB); } return NULL; }
【封装的临界区类】
////////////////////////////////////////////////////////////////////////// // CopyRight(c) 2009, YOYO, All Rights Reserved. // Author: LIN YiQian // Created: 2009/09/16 // Describe: 封装的临界区类 ////////////////////////////////////////////////////////////////////////// #ifndef _MULTITHREAD_CRITICALLOCK_H_ #define _MULTITHREAD_CRITICALLOCK_H_ #if _MSC_VER > 1000 #pragma once #endif #include <Windows.h> class CCriticallLock { public: CCriticallLock(void); ~CCriticallLock(void); public: void Lock(void); void Unlock(void); private: CRITICAL_SECTION m_objCriticalSection; }; #endif // end of define _MULTITHREAD_CRITICALLOCK_H_
////////////////////////////////////////////////////////////////////////// // CopyRight(c) 2009, YOYO, All Rights Reserved. // Author: LIN YiQian // Created: 2009/09/16 // Describe: 封装的临界区类 ////////////////////////////////////////////////////////////////////////// #include "CriticallLock.h" CCriticallLock::CCriticallLock(void) { InitializeCriticalSection(&m_objCriticalSection); } CCriticallLock::~CCriticallLock(void) { DeleteCriticalSection(&m_objCriticalSection); } void CCriticallLock::Lock() { EnterCriticalSection(&m_objCriticalSection); } void CCriticallLock::Unlock() { LeaveCriticalSection(&m_objCriticalSection); }
////////////////////////////////////////////////////////////////////////// // CopyRight(c) 2009, YOYO, All Rights Reserved. // Author: LIN YiQian // Created: 2009/09/16 // Describe: 封装的临界区类 使用 ////////////////////////////////////////////////////////////////////////// #include "CriticallLock.h" #include <Windows.h> #include <iostream> using namespace std; DWORD WINAPI SellTickets(LPVOID lpParameter); int g_nTickets = 100; CCriticallLock g_objCriticallLock; void main(void) { HANDLE hThread1 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL); HANDLE hThread2 = CreateThread(NULL, 0, SellTickets, new int(2), 0, NULL); HANDLE hThread3 = CreateThread(NULL, 0, SellTickets, new int(3), 0, NULL); CloseHandle(hThread1); CloseHandle(hThread2); CloseHandle(hThread3); Sleep(1000); system("pause"); return; } DWORD WINAPI SellTickets(LPVOID lpParameter) { while (true) { g_objCriticallLock.Lock(); if (g_nTickets > 0) { printf("Thread %d sells ticket: No.%d\n", *((int*)lpParameter), g_nTickets--); } else { break; } g_objCriticallLock.Unlock(); } return NULL; }
【杀死主线程】需要使用DuplicateHandle来获得当前线程的HANDLE,否则不能成功删除主线程。删除后执行TerminateThread的子线程篡位成为主线程。
////////////////////////////////////////////////////////////////////////// // CopyRight(c) 2009, YOYO, All Rights Reserved. // Author: LIN YiQian // Created: 2009/09/16 // Describe: 子线程杀死主线程 演示 ////////////////////////////////////////////////////////////////////////// #include <Windows.h> #include <iostream> using namespace std; DWORD WINAPI ThreadFun(LPVOID lpParameter); void main(void) { HANDLE hMainThread; DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hMainThread, 0, FALSE, DUPLICATE_SAME_ACCESS); HANDLE hThread = CreateThread(NULL, 0, ThreadFun, &hMainThread, 0, NULL); while (true) { printf("主线程运行中 - -..\n"); Sleep(100); } CloseHandle(hThread); return; } DWORD WINAPI ThreadFun(LPVOID lpParameter) { HANDLE hMainThread = *((HANDLE*) lpParameter); TerminateThread(hMainThread, 0); while (true) { printf("子线程运行中。。\n"); Sleep(100); } }