零基础逆向工程36_Win32_10_互斥体_互斥体与临界区的区别

1 引言

讲了第二个内核对象,互斥体。前面已经学过一个内核对象,线程。这节讲两个函数,WaitForSingleObject()和WaitForMultipleObjects()。因此这两个函数是根据内核对象的状态来进行操作的。

临界区:一个进程里面对线程进行互斥的控制。
互斥体:实现跨进程的互斥的控制。多个进程抢同一个全局变量,怎样保证最终只有一个进程来用。

2 ForSingleObject()

DWORD WaitForSingleObject(
  HANDLE hHandle,        // handle to object
  DWORD dwMilliseconds   // time-out interval
);

功能说明:
等待函数可使线程自愿进入等待状态,直到一个特定的内核对象变为已通知状态为止.

hHandle:
内核对象句柄,可以是进程也可以是线程.

dwMilliseconds:
等待时间,单位是毫秒 INFINITE(-1)一直等待

返回值:
WAIT_OBJECT_0(0) 等待对象变为已通知
WAIT_TIMEOUT(0x102) 超时

特别说明:
1、内核对象中的每种对象都可以说是处于已通知或未通知的状态之中
2、这种状态的切换是由Microsoft为每个对象建立的一套规则来决定的
3、当线程正在运行的时候,线程内核对象处于未通知状态
4、当线程终止运行的时候,它就变为已通知状态
5、在内核中就是个BOOL值,运行时FALSE 结束TRUE

代码演示

DWORD WINAPI ThreadProc1(LPVOID lpParameter)    
{     
   for(int i=0;i<5;i++) 
   {  
      printf("+++++++++\n");
      Sleep(1000);
   }  
   return 0;   
}     
      
int main(int argc, char* argv[])    
{     
      
   //创建一个新的线程  
   HANDLE hThread1 = ::CreateThread(NULL, 0, ThreadProc1,   
      NULL, 0, NULL);
      
   DWORD dwCode = ::WaitForSingleObject(hThread1, INFINITE);   
      
   MessageBox(0,0,0,0); 
      
   return 0;   
}     

3 和WaitForMultipleObjects()

DWORD WaitForMultipleObjects(
  DWORD nCount,             // number of handles in array
  CONST HANDLE *lpHandles,  // object-handle array
  BOOL bWaitAll,            // wait option
  DWORD dwMilliseconds      // time-out interval
);

功能说明:同时查看若干个内核对象的已通知状态

nCount:要查看内核对象的数量

lpHandles:内核对象数组

bWaitAll:等到类型 TRUE 等到所有变为已通知 FALSE 只要有一个变为已通知

dwMilliseconds:超时时间

INFINITE一直等待

返回值:
bWaitAll为TRUE时,返回WAIT_OBJECT_0(0) 代码所以内核对象都变成已通知
bWaitAll为FALSE时,返回最先变成已通知的内核对象在数组中的索引

WAIT_TIMEOUT(0x102)

代码演示:

DWORD WINAPI ThreadProc1(LPVOID lpParameter)    
{     
   for(int i=0;i<5;i++) 
   {  
      printf("+++++++++\n");
      Sleep(1000);
   }  
   return 0;   
}     
      
DWORD WINAPI ThreadProc2(LPVOID lpParameter)    
{     
   for(int i=0;i<3;i++) 
   {  
      printf("---------\n");
      Sleep(1000);
   }  
      
   return 0;   
}     
      
      
int main(int argc, char* argv[])    
{     
      
   HANDLE hArray[2]; 
      
   //创建一个新的线程  
   HANDLE hThread1 = ::CreateThread(NULL, 0, ThreadProc1,   
      NULL, 0, NULL);
      
   //创建一个新的线程  
   HANDLE hThread2 = ::CreateThread(NULL, 0, ThreadProc2,   
      NULL, 0, NULL);
      
   hArray[0] = hThread1;   
   hArray[1] = hThread2;   
      
   DWORD dwCode = ::WaitForMultipleObjects(2, hArray,FALSE,INFINITE);   
      
   MessageBox(0,0,0,0); 
      
   return 0;   
}     

4 跨进程的线程控制与互斥体

进程一:
HANDLE g_hMutex = CreateMutex(NULL,FALSE, "XYZ");

进程二:
HANDLE g_hMutex = OpenMutex(MUTEX_ALL_ACCESS,FALSE, "XYZ");
WaitForSingleObject(g_hMutex,INFINITE);

//逻辑代码
ReleaseMutex(g_hMutex);

进程三:
HANDLE g_hMutex = OpenMutex(MUTEX_ALL_ACCESS,FALSE, "XYZ");
WaitForSingleObject(g_hMutex,INFINITE);

//逻辑代码
ReleaseMutex(g_hMutex);

互斥体与临界区的区别:
1、临界区只能用于单个进程间的线程控制.
2、互斥体可以设定等待超时,但临界区不能.
3、线程意外终结时,Mutex可以避免无限等待.
4、Mutex效率没有临界区高.

5 练习项目

做一个抢红包项目,要求如下

第一步:在第一个文本框中输入一个值,比如1000         
第二步:点击抢红包,同时创建3个线程,每个线程循环进行抢红包的操作,每次抢50    
第三步:使用Mutex进行线程控制,当第一个文本框中的值<50时,强红包线程结束.       
特别说明:        
1、四个文本框中的值总和应该为1000  
2、强红包线程每次延时50毫秒. 
3、使用WaitForMultipleObjects监听所有线程,当线程全部结束后       
   调用CloseHandle关闭句柄. 
posted @ 2017-11-19 11:10  flatcc  阅读(481)  评论(0编辑  收藏  举报