1、利用事件对象实现多线程的同步: #include<windows.h>#include<iostream.h> DWORD WINAPI FunProc1( LPVOID lpParameter // thread data); DWORD WINAPI FunProc2( LPVOID lpParameter // thread data); int ticket=100;HANDLE hEvent;void main(){ HANDLE hThread1,hThread2; hThread1=CreateThread(NULL,0,FunProc1,NULL,0,NULL); hThread2=CreateThread(NULL,0,FunProc2,NULL,0,NULL); CloseHandle(hThread1); CloseHandle(hThread2); hEvent=CreateEvent(NULL,false,false,"ticket"); /*该函数为创建事件对象 *第一个参数为NULL,表示使用缺省的安全性 *第二个参数当为true,必须用ResetEvent人工地将事件对象设置为无信号状态 当为false,在一个等待线程被释放后系统将事件对象自动设置为无信号状态 *第三个参数指定事件对象的初始状态,当为true为有信号状态,否则为无信号状态 *第四个参数为事件对象的命名,当为NULL该对象为匿名对象 */ if(hEvent) { if(GetLastError()==ERROR_ALREADY_EXISTS) { cout<<"the Event is exists!"<<endl; return; } } //该函数用于设置事件对象为有信号状态 SetEvent(hEvent); Sleep(4000); CloseHandle(hEvent);} DWORD WINAPI FunProc1( LPVOID lpParameter // thread data){ while(1) { WaitForSingleObject(hEvent,INFINITE); //ResetEvent(hEvent); if(ticket>0) { Sleep(1); cout<<"thead1 is sell ticket:"<<ticket--<<endl; } else break; SetEvent(hEvent); } return 0;} DWORD WINAPI FunProc2( LPVOID lpParameter // thread data){ while(1) { WaitForSingleObject(hEvent,INFINITE); //ResetEvent(hEvent); if(ticket>0) { Sleep(1); cout<<"thead2 is sell ticket:"<<ticket--<<endl; } else break; SetEvent(hEvent); /*人工重置事件对象的做法存在两种问题: *当线程1运行到WaitForSingleObject(hEvent,INFINITE)时间片用完,此时 *事件对象仍然处于有信号状态,线程2也进入到了受保护的语句。两个线程 *都进入了受保护的语句,不能实现线程的同步。 *当将这个程序移植到多CPU的机子上,两个线程同时进行,双方都进入了受 *保护的语句,不能实现线程的同步,人工重置已经不再起作用。 */ } return 0;} /*当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。 *当一个线程得到人工重置事件对象,该事件对象仍然处于信号状态。 *当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。 *当一个线程得到自动重置事件对象,该事件对象仍然处于无信号状态。 */2、利用临界区实现多线程的同步: #include<windows.h>#include<iostream.h> DWORD WINAPI FunProc1( LPVOID lpParameter // thread data); DWORD WINAPI FunProc2( LPVOID lpParameter // thread data); int ticket=100;HANDLE hEvent;void main(){ HANDLE hThread1,hThread2; hThread1=CreateThread(NULL,0,FunProc1,NULL,0,NULL); hThread2=CreateThread(NULL,0,FunProc2,NULL,0,NULL); CloseHandle(hThread1); CloseHandle(hThread2); hEvent=CreateEvent(NULL,false,false,"ticket"); /*该函数为创建事件对象 *第一个参数为NULL,表示使用缺省的安全性 *第二个参数当为true,必须用ResetEvent人工地将事件对象设置为无信号状态 当为false,在一个等待线程被释放后系统将事件对象自动设置为无信号状态 *第三个参数指定事件对象的初始状态,当为true为有信号状态,否则为无信号状态 *第四个参数为事件对象的命名,当为NULL该对象为匿名对象 */ if(hEvent) { if(GetLastError()==ERROR_ALREADY_EXISTS) { cout<<"the Event is exists!"<<endl; return; } } //该函数用于设置事件对象为有信号状态 SetEvent(hEvent); Sleep(4000); CloseHandle(hEvent);} DWORD WINAPI FunProc1( LPVOID lpParameter // thread data){ while(1) { WaitForSingleObject(hEvent,INFINITE); //ResetEvent(hEvent); if(ticket>0) { Sleep(1); cout<<"thead1 is sell ticket:"<<ticket--<<endl; } else break; SetEvent(hEvent); } return 0;} DWORD WINAPI FunProc2( LPVOID lpParameter // thread data){ while(1) { WaitForSingleObject(hEvent,INFINITE); //ResetEvent(hEvent); if(ticket>0) { Sleep(1); cout<<"thead2 is sell ticket:"<<ticket--<<endl; } else break; SetEvent(hEvent); /*人工重置事件对象的做法存在两种问题: *当线程1运行到WaitForSingleObject(hEvent,INFINITE)时间片用完,此时 *事件对象仍然处于有信号状态,线程2也进入到了受保护的语句。两个线程 *都进入了受保护的语句,不能实现线程的同步。 *当将这个程序移植到多CPU的机子上,两个线程同时进行,双方都进入了受 *保护的语句,不能实现线程的同步,人工重置已经不再起作用。 */ } return 0;} /*当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。 *当一个线程得到人工重置事件对象,该事件对象仍然处于信号状态。 *当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。 *当一个线程得到自动重置事件对象,该事件对象仍然处于无信号状态。 */ 3、利用互斥对象实现多线程的同步: #include<windows.h>#include<iostream.h> DWORD WINAPI FunProc1( LPVOID lpParameter // thread data); DWORD WINAPI FunProc2( LPVOID lpParameter // thread data); int ticket=100;HANDLE hMutex;void main(){ HANDLE hThread1,hThread2; hThread1=CreateThread(NULL,0,FunProc1,NULL,0,NULL); hThread2=CreateThread(NULL,0,FunProc2,NULL,0,NULL); /*第一个参数为NULL,表示使用缺省的安全性. *第二个参数表示初始提交栈的大小,保留的地址空间大小是x86机子上页面大小的整数倍。 当小于缺省提交的大小,将使用调用线程的大小。 *第三个参数为线程运行函数的入口地址,主线程的入口函数为main. *第四个参数为给线程传递参数。 *第五个参数为创建线程的控制标志.当为CREATE_SUSPENDED线程暂停,只有在调用 ResumeThread函数时才可继续执行. 当为零的时候创建的线程立即执行。 *第六个参数为接受线程的标识符。 Windows NT: If this parameter is NULL, the thread identifier is not returned. Windows 95 and Windows 98: This parameter may not be NULL. */ CloseHandle(hThread1); CloseHandle(hThread2); //关闭线程句柄可以让线程内核对象的引用计数减1,当计数为零时则释放线程内核对象 hMutex=CreateMutex(NULL,true,"ticket"); /*该函数为创建一个有名字的或者匿名的互斥对象。 *第一个参数为NULL,表示使用缺省的安全性. *第二个参数表示互斥对象初始的拥有者。当为true,该互斥对象被调用线程所拥有。false 反之。 *第三个参数为互斥对象的名字,如果为NULL则为匿名。 */ if(hMutex) { //如果互斥对象已经创建 if(ERROR_ALREADY_EXISTS==GetLastError()) { cout<<"only one instance can run!"<<endl; return; } } WaitForSingleObject(hMutex,INFINITE); /*这个函数将使互斥对象的计数器继续加1,此时互斥对象的计数器变为2 *ReleaseMutex函数使互斥对象的计数器减1,此时互斥对象没有变为已通知状态 */ ReleaseMutex(hMutex); ReleaseMutex(hMutex); //互斥对象只有谁拥有以后才能再释放 cout<<"main hThread is running!"<<endl; //Sleep函数是在指定时间间隔中暂停当前的线程 Sleep(4000); /*主线程暂停,执行副线程*/} DWORD WINAPI FunProc1( LPVOID lpParameter // thread data){/* while(1) { //ReleaseMutex(hMutex);这里释放互斥对象不成功,先前互斥对象的线程ID是主线程,不 是线程1 WaitForSingleObject(hMutex,INFINITE); *该函数为等待互斥对象,当互斥对象处于有信号状态或者在时间间隔中流逝函数返 回 *第一个参数为等待对象的句柄 *第二个参数当为INFINITE,函数永远等待下去不会返回WAIT_TIMEOUT *当为零时函数检测后立即返回。 * if(ticket>0) { Sleep(1);//人为的交换,线程1与线程2交替进行,也会出现问题 cout<<"thead1 is sell ticket:"<<ticket--<<endl; } else break; ReleaseMutex(hMutex); //释放互斥对象的所有权 }*/ WaitForSingleObject(hMutex,INFINITE); cout<<"thread1 is running!"<<endl; /*当进程结束后,系统会自动将互斥对象的ID设为空,计数器设为零 *因此不调用ReleaseMutex函数互斥对象也会被释放。 */ return 0;} DWORD WINAPI FunProc2( LPVOID lpParameter // thread data){/* while(1) { WaitForSingleObject(hMutex,INFINITE); if(ticket>0) { Sleep(1); cout<<"thead2 is sell ticket:"<<ticket--<<endl; } else break; ReleaseMutex(hMutex); } */ WaitForSingleObject(hMutex,INFINITE); cout<<"thread1 is running!"<<endl; return 0;}

评论