正文

实现多线程同步的三种方法及示例2007-03-08 12:37:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/12567/23757.html

分享到:

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;}  

阅读(3465) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册