最近写了了个问题很多的多线程程序,在里面我没有使用互斥对象,用它来探索多线程程序到底是如何运行的,在众多网友的帮助下,得到了很多有意义的结果,现整理如下。(如果有错误的观点,敬请批判)首先说明,我的笔记本是双核的,编译器是VS2010:
int main() { HANDLE hThread =(HANDLE) _beginthreadex(NULL, 0, Fun1Proc, NULL, 0, NULL); CloseHandle(hThread); cout<<"main thread is running"<<endl; return 0; } unsigned int __stdcall Fun1Proc( LPVOID lpParameter) { cout<<"thread1 is running!"<<endl; return 0; }这个程序有两种可能的执行结果:
_CRTIMP2_PURE inline basic_ostream<char, char_traits<char> >& __CLRCALL_OR_CDECL endl(basic_ostream<char, char_traits<char> >& _Ostr) { // insert newline and flush byte stream _Ostr.put('\n'); _Ostr.flush(); return (_Ostr); }与之对应的<<重载方式为:
basic_ostream& operator << ( basic_ostream& (*_Pfn)(basic_ostream&) );
unsigned int __stdcall Fun1Proc( LPVOID lpParameter); int index = 100; int main() { //建议用_beginthreadex创建线程而不是用CreateThread HANDLE hThread =(HANDLE) _beginthreadex(NULL, 0, Fun1Proc, NULL, 0, NULL); CloseHandle(hThread); while((index--) > 0) cout<<"main thread number:"<<index<<endl; return 0; } unsigned int __stdcall Fun1Proc( LPVOID lpParameter) { while((index--) > 0) cout<<"thread1 is number:"<<index<<endl; return 0; }这个程序的打印结果就欢乐了,我挑了其中的一段:
当然这个程序还有其他的问题,对于全局对象,应该使用保护机制保护起来,当一个线程使用完成以后,另一个线程再使用,否则,有可能会出现更加奇葩的错误。
DWORD WINAPI Fun1Proc( LPVOID lpParameter); DWORD WINAPI Fun2Proc( LPVOID lpParameter); int tickets = 100; //HANDLE hMutex; int main() { HANDLE hThread1 = CreateThread(NULL,0,Fun1Proc,NULL,0,NULL); CloseHandle(hThread1); HANDLE hThread2 = CreateThread(NULL,0,Fun2Proc,NULL,0,NULL); CloseHandle(hThread2); // hMutex = CreateMutex(NULL,FALSE,NULL); Sleep(4000); return 0; } DWORD WINAPI Fun1Proc( LPVOID lpParameter) { while(TRUE) { // WaitForSingleObject(hMutex,INFINITE); if(tickets>0) { Sleep(10); cout<<"thread1 sell ticket: "<<tickets--<<endl; } else break; // ReleaseMutex(hMutex); } return 0; } DWORD WINAPI Fun2Proc( LPVOID lpParameter) { while(TRUE) { // WaitForSingleObject(hMutex,INFINITE); if(tickets>0) { Sleep(10); cout<<"thread2 sell ticket: "<<tickets--<<endl; } else break; // ReleaseMutex(hMutex); } return 0; }
我注释掉的,是使用互斥对象保护全局变量的代码。则这个代码会出现问题:会有一个线程卖出第0张票!究其原因,是因为当还有一张票时,一个线程,比如Fun1Proc正在运行,它判断if(tickets>0)为真后,开始睡眠,此时切换到Fun2Proc,它也判断if(tickets>0)为真,开始睡眠,然后切换回Fun1Proc,卖出了最后一张票,并把tickets减为0,整个线程执行完以后,又切换到线程2,(此时tickets为0)然后卖出了第0张票。
关于互斥对象的使用,及其他多线程问题,我们在下一小节中再讨论。