多线程学习笔记
头文件windows.h
创建线程
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId )
该函数在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄。
lpThreadAttributes:指向一个 SECURITY_ATTRIBUTES 结构的指针,该结构决定了线程的安全属性,一般置为 NULL;
dwStackSize:指定了线程的堆栈深度,一般都设置为0;
lpStartAddress:表示新线程开始执行时代码所在函数的地址,即线程的起始地址。一般情况为线程函数名;
lpParameter:指定了线程执行时传送给线程的32位参数,即线程函数的参数;
dwCreationFlags:控制线程创建的附加标志,可以取两种值。如果该参数为0,线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于挂起状态,并不马上执行,直至函数ResumeThread被调用;
lpThreadId:该参数返回所创建线程的ID; 如果创建成功则返回线程的句柄,否则返回NULL
SuspendThread(HANDLE hThread);
该函数用于挂起指定的线程,如果函数执行成功,则线程的执行被终止 .
DWORD ResumeThread(HANDLE hThread);
该函数用于结束线程的挂起状态,执行线程。
VOID ExitThread(DWORD dwExitCode);
该函数用于线程终结自身的执行
BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);
强行终止某一线程的执行
自己写的一个简易的线程类:
1 #include <stdio.h> 2 #include <windows.h> 3 4 class unit { 5 public: 6 void *v; //参数 7 int *ret; //返回值 8 }; 9 10 class THREAD 11 { 12 public: 13 HANDLE hThread; //线程句柄 14 DWORD ThreadID; //线程id 15 LPTHREAD_START_ROUTINE IpStartAddress; //线程函数 16 int ret; //返回值 17 unit u; //将参数和返回值打包传入线程函数 18 THREAD() { //初始化 19 ret = 0; 20 } 21 THREAD(void *ThreadProcess) { //带参数初始化 22 ret = 0; 23 IpStartAddress = (LPTHREAD_START_ROUTINE)ThreadProcess; 24 } 25 void run() { //运行线程 26 if (IpStartAddress != NULL) { 27 u = { NULL,&ret }; 28 hThread = CreateThread(NULL, 0, IpStartAddress, (LPVOID)&u, 0, &ThreadID); 29 } 30 } 31 void run(void *lp) { //运行线程,并传入参数 32 if (IpStartAddress != NULL) { 33 u = { lp,&ret }; 34 hThread = CreateThread(NULL, 0, IpStartAddress, (LPVOID)&u, 0, &ThreadID); 35 } 36 } 37 };
该类可以调用带参数的线程函数或者不带参数的线程函数,线程函数返回值类型为int,将放在ret中
使用:
1 THREAD fightthread; //创建线程类 2 fightthread.IpStartAddress = (LPTHREAD_START_ROUTINE)waitFight;//线程函数赋值 3 fightthread.run(); //运行线程
线程函数定义:
void waitFight(LPVOID pM) { unit* c=(unit*)pM; //参数类型为上边定义的unit类,类里的参数v可以是任意类型的参数 函数体; ...... unit->ret=0; //线程函数返回值赋值 }
一个线程池的实现:
1 #pragma warning(disable: 4530) 2 #pragma warning(disable: 4786) 3 #include <stdio.h> 4 #include <cassert> 5 #include <vector> 6 #include <queue> 7 #include <windows.h> 8 using namespace std; 9 10 class ThreadJob //工作基类 11 { 12 public: 13 //供线程池调用的虚函数 14 virtual void DoJob(void *pPara) = 0; 15 }; 16 17 class ThreadPool 18 { 19 public: 20 //dwNum 线程池规模 21 ThreadPool(DWORD dwNum = 4) : _lThreadNum(0), _lRunningNum(0) 22 { 23 InitializeCriticalSection(&_csThreadVector); 24 InitializeCriticalSection(&_csWorkQueue); 25 _EventComplete = CreateEvent(0, false, false, NULL); 26 _EventEnd = CreateEvent(0, true, false, NULL); 27 _SemaphoreCall = CreateSemaphore(0, 0, 0x7FFFFFFF, NULL); 28 _SemaphoreDel = CreateSemaphore(0, 0, 0x7FFFFFFF, NULL); 29 assert(_SemaphoreCall != INVALID_HANDLE_VALUE); 30 assert(_EventComplete != INVALID_HANDLE_VALUE); 31 assert(_EventEnd != INVALID_HANDLE_VALUE); 32 assert(_SemaphoreDel != INVALID_HANDLE_VALUE); 33 AdjustSize(dwNum <= 0 ? 4 : dwNum); 34 } 35 ~ThreadPool() 36 { 37 DeleteCriticalSection(&_csWorkQueue); 38 CloseHandle(_EventEnd); 39 CloseHandle(_EventComplete); 40 CloseHandle(_SemaphoreCall); 41 CloseHandle(_SemaphoreDel); 42 vector<ThreadItem*>::iterator iter; 43 for (iter = _ThreadVector.begin(); iter != _ThreadVector.end(); iter++) 44 { 45 if (*iter) 46 delete *iter; 47 } 48 DeleteCriticalSection(&_csThreadVector); 49 } 50 //调整线程池规模 51 int AdjustSize(int iNum) 52 { 53 if (iNum > 0) 54 { 55 ThreadItem *pNew; 56 EnterCriticalSection(&_csThreadVector); 57 for (int _i = 0; _i<iNum; _i++) 58 { 59 _ThreadVector.push_back(pNew = new ThreadItem(this)); 60 assert(pNew); 61 pNew->_Handle = CreateThread(NULL, 0, DefaultJobProc, pNew, 0, NULL); 62 // set priority 63 SetThreadPriority(pNew->_Handle, THREAD_PRIORITY_BELOW_NORMAL); 64 assert(pNew->_Handle); 65 } 66 LeaveCriticalSection(&_csThreadVector); 67 } 68 else 69 { 70 iNum *= -1; 71 ReleaseSemaphore(_SemaphoreDel, iNum > _lThreadNum ? _lThreadNum : iNum, NULL); 72 } 73 return (int)_lThreadNum; 74 } 75 //调用线程池 76 void Call(void(*pFunc)(void *), void *pPara = NULL) 77 { 78 assert(pFunc); 79 EnterCriticalSection(&_csWorkQueue); 80 _JobQueue.push(new JobItem(pFunc, pPara)); 81 LeaveCriticalSection(&_csWorkQueue); 82 ReleaseSemaphore(_SemaphoreCall, 1, NULL); 83 } 84 //调用线程池 85 inline void Call(ThreadJob * p, void *pPara = NULL) 86 { 87 Call(CallProc, new CallProcPara(p, pPara)); 88 } 89 //结束线程池, 并同步等待 90 bool EndAndWait(DWORD dwWaitTime = INFINITE) 91 { 92 SetEvent(_EventEnd); 93 return WaitForSingleObject(_EventComplete, dwWaitTime) == WAIT_OBJECT_0; 94 } 95 //结束线程池 96 inline void End() 97 { 98 SetEvent(_EventEnd); 99 } 100 inline DWORD Size() 101 { 102 return (DWORD)_lThreadNum; 103 } 104 inline DWORD GetRunningSize() 105 { 106 return (DWORD)_lRunningNum; 107 } 108 bool IsRunning() 109 { 110 return _lRunningNum > 0; 111 } 112 protected: 113 //工作线程 114 static DWORD WINAPI DefaultJobProc(LPVOID lpParameter = NULL) 115 { 116 ThreadItem *pThread = static_cast<ThreadItem*>(lpParameter); 117 assert(pThread); 118 ThreadPool *pThreadPoolObj = pThread->_pThis; 119 assert(pThreadPoolObj); 120 InterlockedIncrement(&pThreadPoolObj->_lThreadNum); 121 HANDLE hWaitHandle[3]; 122 hWaitHandle[0] = pThreadPoolObj->_SemaphoreCall; 123 hWaitHandle[1] = pThreadPoolObj->_SemaphoreDel; 124 hWaitHandle[2] = pThreadPoolObj->_EventEnd; 125 JobItem *pJob; 126 bool fHasJob; 127 for (;;) 128 { 129 DWORD wr = WaitForMultipleObjects(3, hWaitHandle, false, INFINITE); 130 //响应删除线程信号 131 if (wr == WAIT_OBJECT_0 + 1) 132 break; 133 //从队列里取得用户作业 134 EnterCriticalSection(&pThreadPoolObj->_csWorkQueue); 135 if (fHasJob = !pThreadPoolObj->_JobQueue.empty()) 136 { 137 pJob = pThreadPoolObj->_JobQueue.front(); 138 pThreadPoolObj->_JobQueue.pop(); 139 assert(pJob); 140 } 141 LeaveCriticalSection(&pThreadPoolObj->_csWorkQueue); 142 //受到结束线程信号 确定是否结束线程(结束线程信号 && 是否还有工作) 143 if (wr == WAIT_OBJECT_0 + 2 && !fHasJob) 144 break; 145 if (fHasJob && pJob) 146 { 147 InterlockedIncrement(&pThreadPoolObj->_lRunningNum); 148 pThread->_dwLastBeginTime = GetTickCount(); 149 pThread->_dwCount++; 150 pThread->_fIsRunning = true; 151 pJob->_pFunc(pJob->_pPara); //运行用户作业 152 delete pJob; 153 pThread->_fIsRunning = false; 154 InterlockedDecrement(&pThreadPoolObj->_lRunningNum); 155 } 156 } 157 //删除自身结构 158 EnterCriticalSection(&pThreadPoolObj->_csThreadVector); 159 pThreadPoolObj->_ThreadVector.erase(find(pThreadPoolObj->_ThreadVector.begin(), pThreadPoolObj->_ThreadVector.end(), pThread)); 160 LeaveCriticalSection(&pThreadPoolObj->_csThreadVector); 161 delete pThread; 162 InterlockedDecrement(&pThreadPoolObj->_lThreadNum); 163 if (!pThreadPoolObj->_lThreadNum) //所有线程结束 164 SetEvent(pThreadPoolObj->_EventComplete); 165 return 0; 166 } 167 //调用用户对象虚函数 168 static void CallProc(void *pPara) 169 { 170 CallProcPara *cp = static_cast<CallProcPara *>(pPara); 171 assert(cp); 172 if (cp) 173 { 174 cp->_pObj->DoJob(cp->_pPara); 175 delete cp; 176 } 177 } 178 //用户对象结构 179 struct CallProcPara 180 { 181 ThreadJob* _pObj;//用户对象 182 void *_pPara;//用户参数 183 CallProcPara(ThreadJob* p, void *pPara) : _pObj(p), _pPara(pPara) { }; 184 }; 185 //用户函数结构 186 struct JobItem 187 { 188 void(*_pFunc)(void *);//函数 189 void *_pPara; //参数 190 JobItem(void(*pFunc)(void *) = NULL, void *pPara = NULL) : _pFunc(pFunc), _pPara(pPara) { }; 191 }; 192 //线程池中的线程结构 193 struct ThreadItem 194 { 195 HANDLE _Handle; //线程句柄 196 ThreadPool *_pThis; //线程池的指针 197 DWORD _dwLastBeginTime; //最后一次运行开始时间 198 DWORD _dwCount; //运行次数 199 bool _fIsRunning; 200 ThreadItem(ThreadPool *pthis) : _pThis(pthis), _Handle(NULL), _dwLastBeginTime(0), _dwCount(0), _fIsRunning(false) { }; 201 ~ThreadItem() 202 { 203 if (_Handle) 204 { 205 CloseHandle(_Handle); 206 _Handle = NULL; 207 } 208 } 209 }; 210 std::queue<JobItem *> _JobQueue; //工作队列 211 std::vector<ThreadItem *> _ThreadVector; //线程数据 212 CRITICAL_SECTION _csThreadVector, _csWorkQueue; //工作队列临界, 线程数据临界 213 HANDLE _EventEnd, _EventComplete, _SemaphoreCall, _SemaphoreDel;//结束通知, 完成事件, 工作信号, 删除线程信号 214 long _lThreadNum, _lRunningNum; //线程数, 运行的线程数 215 };
使用:
ThreadPool tp(10); tp.Call(函数名[,函数参数]);