网站已经改版为Wordpress版本,这里是旧版本的快照,请不要在页面中留言.

C++线程同步学习 ① 互斥体Mutex

   

注:本文中所使用的是C++的示例.


     如果程序启动了多个线程,那么就存在多个线程对同一资源进行抢占的问题。在单线程的应用程序中,读取统一资源不会出现意想不到的事情,但是对于多个线程的程序,同时操作同一个资源的时候就会出现我们不期望的结果.为了解决这一问题,提出了线程同步的概念.

·    线程同步的基本方法

     线程同步的基本方法有很多,最常用的有互斥(CMutex)、临界(CriticalSection)、信号量(Semaphore)、事件(Event)等。这4中方法分别在Win32MFC两种方式下个有一种实现,MFC中其实是对win32下的封装,使用起来较为方便。

 

    互斥(CMutex) :

    示例代码下载:(VC 6.0)工程:

    解压密码 yscode

     http://pan.baidu.com/s/1kTJVVOb


    互斥 就是一个线程对共享资源进行访问时排斥其他的线程。在Win32中过CreateMutex进行创建,在程序运行的时候只有拥有互斥对象的线程才有访问资源的权利。只有当拥有互斥对象的线程通过ReleaseMutex函数交出互斥对象,其他线程才能拥有对资源的访问权利.MFC中,直接通过CMutex创建对象,通过CMeutex::Lock()CMutex::Unlock()函数进行锁定和解锁.

 

//下面是一个 控制台的 同步示例代码,其中 SIGN 是一个BOOL值,为TRUE的时候开启同步,为FALSE的时候关闭线程同步,你可以对比一下不同情况下的输出.

 

//*********************这一段是使用Win32的方法
#include <windows.h>
#include <iostream>
using namespace std;

//!!!!!!!!!!!!!!!!通过一个标记,开启或者关闭同步,来查看效果
BOOL SIGN = TRUE;

//一个数组用于打印显示使用
int Arry[20];

//用于线程同步的互斥体句柄
HANDLE hMutex = NULL;
//*********************************线程1,对数组内的数值进行赋值0~19
DWORD CALLBACK ThreadProc1(LPVOID lp)
{
	
	//等待互斥体,如果没有拥有互斥体将会等待 INFINITE ms时间
	if(SIGN)
	  WaitForSingleObject(hMutex,INFINITE);
	
	//让线程先睡一下,让线程2有机会执行 
	//如果没有同步的话,线程2是不会等待1完成的,那么输出的数值是不对的
	Sleep(100);
	for (int i=0;i<20;i++)
	{
		Arry[i] = i;
	}

	if(SIGN)
		ReleaseMutex(hMutex);//释放互斥体
	return 0;
}
//*********************************线程2,打印数组
DWORD CALLBACK ThreadProc2(LPVOID lp)
{
        //等待互斥体,如果没有拥有互斥体将会等待 INFINITE ms时间
	if(SIGN)
	  WaitForSingleObject(hMutex,INFINITE);

	for (int i=0;i<20;i++)
	{
		cout<<"Arr["<<i<<"]: "<<Arry[i]<<endl;
	}

	if(SIGN)
		ReleaseMutex(hMutex);//释放互斥体
	return 0;
}


int main()
{
	memset(Arry,0xFF,sizeof(Arry));//初始化数组
        
        //创建一个互斥体,参数2指定 没有线程拥有这个互斥体
	if(SIGN)
		hMutex = CreateMutex(NULL,FALSE,NULL);
	
	//开始线程1
	DWORD tid = 0;
	HANDLE hThread = INVALID_HANDLE_VALUE;
	//开启线程1
	hThread = CreateThread(0,0,ThreadProc1,0,0,&tid);
	if(hThread!=INVALID_HANDLE_VALUE){CloseHandle(hThread);}
	
	//开启线程2
	hThread = CreateThread(0,0,ThreadProc2,0,0,&tid);
	if(hThread!=INVALID_HANDLE_VALUE){CloseHandle(hThread);}


	//防止主线程退出
	while(TRUE){
		Sleep(1000);
	}

	return 0;
}

 

//下面是一个使用MFC的方法写的互斥体同步,由于是在控制台写的,所以要引入MFC的头文件,并且需要将工程的属性设置为使用MFC的静态库/共享库

 

//*******************************************这一段是使用的是MFC的方法

//因为我这里使用的是 控制台的程序,要使用MFC的话
//引入MFC的头文件,还有就是工程属性 要使用 MFC静态库或者动态库才行
#include <AfxWin.h>
#include <afxmt.h>
#include <iostream>
using namespace std;
 
//通过一个标记,开启或者关闭同步,来查看效果
BOOL SIGN = TRUE;
 
//一个数组用于打印显示使用
int Arry[20];
 
//创建一个CMutex的互斥体
CMutex MuTex(FALSE,NULL);
//*********************************线程1,对数组内的数值进行赋值0~19
DWORD CALLBACK ThreadProc1(LPVOID lp)
{
        
        
 
         if(SIGN)
                   MuTex.Lock();//等待互斥体,如果没有拥有互斥体将会等待 INFINITE ms时间
        
         //让线程先睡一下,让线程2有机会执行 
         //如果没有同步的话,线程2是不会等待1完成的,那么输出的数值是不对的
         Sleep(100);
         for (int i=0;i<20;i++)
         {
             Arry[i] = i;
         }
 
         if(SIGN)
              MuTex.Unlock();
         return 0;
}
//*********************************线程2,打印数组
DWORD CALLBACK ThreadProc2(LPVOID lp)
{
         if(SIGN)
                   MuTex.Lock();
         for (int i=0;i<20;i++)
         {
            cout<<"Arr["<<i<<"]: "<<Arry[i]<<endl;
         }
 
         if(SIGN)
            MuTex.Unlock();
         return 0;
}
 
 
int main()
{
         memset(Arry,0xFF,sizeof(Arry));//初始化数组
 
         //开始线程1
         DWORD tid = 0;
         HANDLE hThread = INVALID_HANDLE_VALUE;
         //开启线程1
         hThread = CreateThread(0,0,ThreadProc1,0,0,&tid);
         if(hThread!=INVALID_HANDLE_VALUE){CloseHandle(hThread);}
        
         //开启线程2
         hThread = CreateThread(0,0,ThreadProc2,0,0,&tid);
         if(hThread!=INVALID_HANDLE_VALUE){CloseHandle(hThread);}
 
 
         //防止主线程退出
         while(TRUE){
                   Sleep(1000);
         }
 
    return 0;
}


示例代码下载:(VC 6.0)工程:

    解压密码 yscode

     http://pan.baidu.com/s/1kTJVVOb


本文出自 悠然品鉴,转载请注明出处:http://www.youranshare.com/blog/sid/38.html


  • 标签:
  • 线程同步
  • 互斥体
  • Mutex
网站已经改版为Wordpress版本,这里是旧版本的快照,请不要在页面中留言.