孙鑫mfc学习笔记第十五课

来源:互联网 发布:瑞安. 艾戈尔德 知乎 编辑:程序博客网 时间:2024/06/05 22:39

多线程程序的编写,多线程应用中容易出现的问题。互斥对象的讲解,如何使用互斥对象来实现多线程的同步。如何利用命名互斥对象保证应用程序只有一个实例运行。应用多线程编写网络聊天室程序。

互斥对象

互斥对象(mutex)属于内核对象,它能够确保线程拥有对单个资源的互斥访问权。

互斥对象包含一个使用数量,一个线程ID和一个计数器。

ID用于标识系统中的哪个线程当前拥有互斥对象,计数器用于指明该线程拥有互斥对象的次数。

  1. #include <windows.h> 
  2. #include <iostream.h> 
  3. //声明线程入口函数原型 
  4. DWORD WINAPI Fun1Proc(  LPVOID lpParameter ); 
  5. DWORD WINAPI Fun2Proc(  LPVOID lpParameter ); 
  6. int tickets = 100; //要销售的票数还剩下100张 
  7. //这100张票由Fun1Proc与Fun2Proc两个线程负责销售 
  8.  
  9. HANDLE hMutex;//互斥对象句柄 
  10.  
  11. void main() 
  12. {    
  13.     HANDLE  hThread1,hThread2; 
  14.     hThread1 = CreateThread(            //创建线程 
  15.         NULL,   //使用缺省的安全性 
  16.         0,      //指定初始提交栈的大小 
  17.         Fun1Proc,//指定线程入口函数地址 
  18.         NULL,   //传递给线程的参数 
  19.         0,      //附加标记,0表示线程创建后立即运行。值为CREATE_SUSPENDED,创建一个挂起的线程  
  20.         NULL);  //线程ID,在Win98/95中不能设置为NULL 
  21.     CloseHandle(hThread1); 
  22.     hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL); 
  23.     CloseHandle(hThread2); 
  24. //  cout<<"main thread is running"<<endl; 
  25. //  hMutex = CreateMutex(NULL, FALSE,NULL); //创建一个匿名的互斥对象 
  26.  
  27.     //创建一个命名的互斥对象 
  28.     hMutex = CreateMutex(NULL,//默认安全性 
  29.         TRUE,//初始拥有者,调用线程拥有所用权 
  30.         "MuName");//命名的互斥对象 
  31.          
  32.     if(hMutex)          //是程序只能运行一次 
  33.     {//判断是不是第一次创建的互斥对象 
  34.         if(ERROR_ALREADY_EXISTS == GetLastError()) 
  35.         {//如果为真,说明互斥对象已经创建 
  36.             cout<<"已经有一个实例在运行了,只能有一个实例运行同时运行。"<<endl; 
  37.             return
  38.         } 
  39.     } 
  40.     WaitForSingleObject(hMutex,INFINITE); 
  41.         //因为请求的互斥对象线程ID与拥有互斥对象线程ID相同, 
  42.         //可以再次请求成功,计数器加1 
  43.     ReleaseMutex(hMutex);  //第一次释放,计数器减1,但仍有信号 
  44.     ReleaseMutex(hMutex);  //再一次释放,计数器为零 
  45.  
  46.     while(tickets>0)    { Sleep(4000);} 
  47. }//endof main() 
  48. /*------------实现线程入口函数Fun1Proc---------------*/ 
  49. DWORD WINAPI Fun1Proc(  LPVOID lpParameter ) 
  50. {    
  51.     while(TRUE) 
  52.     { 
  53.         //请求互斥对象 
  54.         WaitForSingleObject(hMutex,//处于未通知的状态则等待 
  55.             INFINITE);//时间流逝则返回,INFINITE永远等待 
  56.              
  57.         if(tickets>0) 
  58.         {Sleep(1); 
  59.             cout<<"thread 1 sell ticket: "
  60.             cout<<tickets--<<endl; 
  61.         } 
  62.         else   
  63.             break
  64.         ReleaseMutex(hMutex);//释放互斥对象 
  65.  
  66.     } 
  67.     return 0; 
  68. }   ///endof Fun1Proc() 
  69.  
  70. /*-----------实现线程入口函数Fun2Proc--------------*/ 
  71. DWORD WINAPI Fun2Proc(  LPVOID lpParameter ) 
  72. {    
  73.     while(TRUE) 
  74.     { 
  75.         WaitForSingleObject(hMutex,INFINITE); 
  76.         if(tickets>0) 
  77.         {Sleep(1); 
  78.             cout<<"thread 2 sell ticket: "
  79.             cout<<tickets--<<endl; 
  80.         } 
  81.         else 
  82.             break
  83.         ReleaseMutex(hMutex); 
  84.     } 
  85.     return 0; 
  86. }   ///endof Fun1Proc() 
  87.  
  88.  
  89.  
  90. BOOL CChatApp::InitInstance()//注意要包含#include <AfxSock.h> 
  91.     if(!AfxSocketInit())//加载套接字库,进行版本协商,可以确保程序结束终结套接字库 
  92.     { 
  93.         AfxMessageBox("加载套接字失败!"); 
  94.         return FALSE; 
  95.     } 
  96.  
  97.  
  98. BOOL CChatDlg::InitSocket() 
  99. {//初始化套接字: 
  100.     SOCKET m_socket; 
  101.     m_socket = socket(AF_INET,SOCK_DGRAM,0); 
  102.     if(INVALID_SOCKET == m_socket) 
  103.     { 
  104.         AfxMessageBox("套接字创建失败"); 
  105.         return FALSE;  
  106.     } 
  107.     SOCKADDR_IN addrSock; 
  108.     addrSock.sin_family=AF_INET; 
  109.     addrSock.sin_port=htons(6000); 
  110.     addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY); 
  111.         //INADDR_ANY表示接收任意IP地址 
  112.     //绑定 
  113.     int retval;//用来接收bind返回值 
  114.     retval=bind(m_socket,(SOCKADDR*)&addrSock, 
  115.         sizeof(SOCKADDR)); 
  116.     if(SOCKET_ERROR==retval) 
  117.     {//绑定失败 
  118.         closesocket(m_socket); 
  119.         AfxMessageBox("绑定失败"); 
  120.         return FALSE; 
  121.     } 
  122.     return TRUE;