线程的同步—CMutex 和 CSemaphore 类

CMutex 类
互斥对象与临界区对象很像.互斥对象与临界区对象的不同在于:互斥对象可以在进程间使用,而临界区对象只能在同一进程的各线程间使用。当然,互斥对象也可以用于同一进程的各个线程间,但是在这种情况下,使用临界区会更节省系统资源,更有效率。

CSemaphore 类
当需要一个计数器来限制可以使用某个线程的数目时,可以使用“信号量”对象。CSemaphore 类的对象保存了对当前访问某一指定资源的线程的计数值,该计数值是当前还可以使用该资源的线程的数目。如果这个计数达到了零,则所有对这个CSemaphore 类对象所控制的资源的访问尝试都被放入到一个队列中等待,直到超时或计数值不为零时为止。一个线程被释放已访问了被保护的资源时,计数值减1;一个线程完成了对被控共享资源的访问时,计数值增 1。这个被CSemaphore 类对象所控制的资源可以同时接受访问的最大线程数在该对象的构建函数中指定。

CSemaphore 类的构造函数原型及参数说明如下:

CSemaphore ( LONG lInitialCount = 1 ,
            
LONG lMaxCount = 1 ,
            
LPCTSTR pstrName = NULL ,
            
LPSECURITY_ATTRIBUTES lpsaAttributes = NULL ) ;

lInitialCount:信号量对象的初始计数值,即可访问线程数目的初始值;
lMaxCount:信号量对象计数值的最大值,该参数决定了同一时刻可访问由信号量保护的资源的线程最大数目;
后两个参数在同一进程中使用一般为NULL,不作过多讨论;

在用 CSemaphore 类的构造函数创建信号量对象时要同时指出允许的最大资源计数和当前可用资源计数。一般是将当前可用资源计数设置为最大资源计数,每增加一个线程对共享资源的访问,当前可用资源计数就会减1,只要当前可用资源计数是大于0的,就可以发出信号量信号。但是当前可用计数减小到0 时,则说明当前占用资源的线程数已经达到了所允许的最大数目,不能再允许其它线程的进入,此时的信号量信号将无法发出。线程在处理完共享资源后,应在离开的同时通过 ReleaseSemaphore() 函数将当前可用资源数加1。

下面给出一个简单实例来说明 CSemaphore 类的用法。
建立一个基于对话框的工程 MultiThread10,在对话框 IDD_MULTITHREAD10_DIALOG 中加入一个按钮和三个编辑框控件,按钮的 ID 为 IDC_START,标题为“同时写‘A’、‘B’、‘C’”;三个编辑框的 ID 分别为 IDC_A、IDC_B 和 IDC_C,属性都选中 Read -only;
在 MultiThread10Dlg.h 文件中声明两个线程函数:

UINT WriteA ( LPVOID pParam ) ;
UINT WriteB ( LPVOID pParam ) ;
UINT WriteC ( LPVOID pParam ) ;

使用 ClassWizard 分别给 IDC_A、IDC_B 和 IDC_C 添加 CEdit 类变量 m_ctrlA、m_ctrlB 和 m_ctrlC;
在 MultiThread10Dlg.cpp 文件中添加如下内容:
为了文件中能够正确使用同步类,在文件开头添加:

#include " afxmt.h "

定义信号量对象和一个字符数组,为了能够在不同线程间使用,定义为全局变量:

CSemaphore semaphoreWrite ( 2 , 2 ) ; //资源最多访问线程2个,当前可访问线程数2个
char g_Array [ 10 ] ;

添加三个线程函数:

UINT WriteA ( LPVOID pParam )
{
 
CEdit * pEdit = ( CEdit * ) pParam ;
 
pEdit -> SetWindowText ( "" ) ;
 
WaitForSingleObject ( semaphoreWrite . m_hObject , INFINITE ) ;
 
CString str ;
 
for ( int i = 0 ; i < 10 ; i ++ )
 
{
        
pEdit -> GetWindowText ( str ) ;
 
g_Array [ i ] ='' A '';
 
str = str + g_Array [ i ] ;
    
pEdit -> SetWindowText ( str ) ;
 
Sleep ( 1000 ) ;
 
}
 
ReleaseSemaphore ( semaphoreWrite . m_hObject , 1 , NULL ) ;
 
return 0 ;
 
}
UINT WriteB ( LPVOID pParam )
{
 
CEdit * pEdit = ( CEdit * ) pParam ;
 
pEdit -> SetWindowText ( "" ) ;
 
WaitForSingleObject ( semaphoreWrite . m_hObject , INFINITE ) ;
 
CString str ;
 
for ( int i = 0 ; i < 10 ; i ++ )
 
{
 
        
pEdit -> GetWindowText ( str ) ;
 
g_Array [ i ] ='' B '';
 
str = str + g_Array [ i ] ;
    
pEdit -> SetWindowText ( str ) ;
 
Sleep ( 1000 ) ;
 
}
 
ReleaseSemaphore ( semaphoreWrite . m_hObject , 1 , NULL ) ;
 
return 0 ;
 
}
UINT WriteC ( LPVOID pParam )
{
 
CEdit * pEdit = ( CEdit * ) pParam ;
 
pEdit -> SetWindowText ( "" ) ;
 
WaitForSingleObject ( semaphoreWrite . m_hObject , INFINITE ) ;
 
for ( int i = 0 ; i < 10 ; i ++ )
 
{
 
g_Array [ i ] ='' C '';
    
pEdit -> SetWindowText ( g_Array ) ;
 
Sleep ( 1000 ) ;
 
}
 
ReleaseSemaphore ( semaphoreWrite . m_hObject , 1 , NULL ) ;
 
return 0 ;
 
}

这三个线程函数不再多说。在信号量对象有信号的状态下,线程执行到 WaitForSingleObject 语句处继续执行,同时可用线程数减1;若线程执行到 WaitForSingleObject 语句时信号量对象无信号,线程就在这里等待,直到信号量对象有信号线程才往下执行。
双击按钮IDC_START,添加其响应函数:

void CMultiThread10Dlg :: OnStart ()
{
 
CWinThread * pWriteA = AfxBeginThread ( WriteA ,
  &
m_ctrlA ,
 
THREAD_PRIORITY_NORMAL ,
 
0 ,
 
CREATE_SUSPENDED ) ;
 
pWriteA -> ResumeThread () ;
 
 
CWinThread * pWriteB = AfxBeginThread ( WriteB ,
  &
m_ctrlB ,
 
THREAD_PRIORITY_NORMAL ,
 
0 ,
 
CREATE_SUSPENDED ) ;
 
pWriteB -> ResumeThread () ;
 
 
CWinThread * pWriteC = AfxBeginThread ( WriteC ,
  &
m_ctrlC ,
 
THREAD_PRIORITY_NORMAL ,
 
0 ,
 
CREATE_SUSPENDED ) ;
 
pWriteC -> ResumeThread () ;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值