正文

多线程:线程同步--使用临界区,使用信号量2006-09-24 15:17:00

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

分享到:

学习多线程之三:线程同步--使用互斥

下载本文配套代码

互斥跟临界区很相似,便远比临界区复杂。因为使用互斥不仅仅能够在同一应用程序不同线程中实现资源的安全共享,而且可以在不同应用程序的线程之间实现对资源的安全共享。通过CMutex来完成线程间的互质,即:CMutex Mutext;



从而我们可以这样来定义数据对象:

#include "afxmt.h"
 
class CDataArray
{
private:
               int iArray[10];
    CMutex Mutex;
public:
    CDataArray(){};
    ~CDataArray(){};
 
    void SetData(int iValue);
    void GetDataArray(int aArray[10]);
};

成员函数实现如下:

void CDataArray::SetData(int iValue)
{
               CSingleLock SingleLock(&Mutex);
               SingleLock.Lock();
               for (int i=0;i<10;i++)
                               iArray[i]=iValue;
}
 
void CDataArray::GetDataArray(int aArray[10])
{
               CSingleLock SingleLock(&Mutex);
               SingleLock.Lock();
               for (int i=0;i<10;i++)
                               aArray[i]=iArray[i];
}

为了访问一个互斥对象,务必建立一个CSingleLockCMultiLock对象,用于访问控制。如果互斥没有被线程占用,那么当前的调用线程可以成为互斥的占用者。要实现对互斥的访问,就要调用CSingleLock的成员函数Lock(),即:
SingleLock.Lock();
如果一个线程占用了互斥,那么系统将挂起当前的调用线程,直到这个互斥被释放为止,这时,被挂起的线程将被唤醒并取得对互斥的控制。
释放互斥是通过调用CSingleLock的成员函数UnLock()来实现的。CDataArray的成员函数在退出时,将自动进行解锁操作。因为CSingleLock被创建在椎栈上,系统自动完成对UnLock()的调用。

 

 /////////////////////////////////////////////////////////////////////////////// 


绝对同步,下面是我自己添加测试的代码
UINT Thread_ReadProc(LPVOID param)
{
int aArray[10];
for (int i=0;i<20;i++)
{
DataArray.GetDataArray(aArray);
char str[255];
str[0]=0;
for (int j=0;j<10;j++)
{
int len=strlen(str);
wsprintf(&str[len],"%d",aArray[j]);
}
TRACE1("%s\n",str);
}
return 0;
}
void CDataArray::SetData(int iValue)
{
CSingleLock SingleLock(&Mutex);
SingleLock.Lock();
for (int i=0;i<10;i++)
{
iArray[i]=iValue;
TRACE1("set i = %d\n", iValue );
::Sleep(2000);
}
}
这两个函数经过修改了,延时加长,就可以清楚的看到结果
( fosky
发表于 2006-6-23 16:46:00)
 
 /////////////////////////////////////////////////////////////////////////////// 

 
1
楼那个更逗,怎么不把机箱型号也写出来 ( hexiyajin 发表于
2006-5-8 12:06:00)
 
绝对同步,你们怎么测的,虽然我不是lz,但是用眼睛看这么简单的代码也是同步的啊。 ( hexiyajin 发表于
2006-5-8 12:05:00)
 
我真不明白.它的4篇文章至少有2,3篇都有错误,代码根本无法实现同步.竟然还能被选中进入知识库
?
( greenjava
发表于
2005-7-11 13:04:00)
 
你自己测试一下同步吗?


我测试了一下,结论:不同步

 

 

学习多线程之四:线程同步--使用信号量
 

下载本文配套代码

除了使用临界区与互斥可以完成线程间的同步外,还可以使用信号量CSemaphore。使用信号量还有一个好处便是:信号允许多个线程同时使用共享资源,这便与操作系统中的PV操作有些雷同的地方。它指出了同时访问共享资源的线程最大数目。

在信号量内部有一个计数器,当有线程访问共享资源时,计数器将自动递减,当它为0时,不再允许其他线程对共享资源的访问,直到有一个线程释放共享资源,从而完成对共享资源的保护。





在建立一个信号量时必须提供一个初始化值和一个最大计数值,如:

CSemaphore Semaphore(2,2);

可以在类的构造函数中动态地创建CSemaphore对象,如:

Semaphore=new CSemaphore(2,2);

信号量CSemaphore被建立后,就可以准备用它来对共享资源进行访问计数。要完成计数处理,首先应建立一个CSingleLockCMultiLock对象,如:

CSingleLock SingleLock(Semaphore);

要减小这个信号Semaphore的计数值,只须调用CSingleLock对象的成员函数Lock()即可:

SingleLock.Lock();

同样,通过调用UnLock()来释放这个信号量,即:

SingleLock.UnLock();

从而我们可这样来申明类:

#include "afxmt.h"
 
class CSharedResource
{
private:
               CSemaphore* ptrSemaphore;
public:
               CSharedResource();
               ~CSharedResource();  
               void AccessResource();
};

在构造函数中完成对信号对象的创建:

CSharedResource::CSharedResource()
{
               ptrSemaphore=new CSemaphore(2,2);
}

在析构函数中完成对信号对象的释放:

CSharedResource::~CSharedResource()
{
               delete ptrSemaphore;
}

用以下过程来访问共享资源:

void CSharedResource::AccessResource()
{
               CSingleLock SingleLock(ptrSemaphore);
               SingleLock.Lock();
               /* ......
                 资源访问
               */
               Sleep(1000);
}

再建立使用信号量的线程函数:

UINT Thread_Proc1(LPVOID param)
{
               SharedResource.AccessResource();
               ::MessageBox((HWND)param,"Thread #1 had accessed the Semaphore!","Thread Proc1",MB_OK);
               return 0;
}
 
UINT Thread_Proc2(LPVOID param)
{
               SharedResource.AccessResource();
               ::MessageBox((HWND)param,"Thread #2 had accessed the Semaphore!","Thread Proc2",MB_OK);
               return 0;
}
 
UINT Thread_Proc3(LPVOID param)
{
               SharedResource.AccessResource();
               ::MessageBox((HWND)param,"Thread #3 had accessed the Semaphore!","Thread Proc3",MB_OK);
               return 0;
}

再用以下代码执行各个线程函数:

HWND hWnd=GetSafeHwnd();
AfxBeginThread(Thread_Proc1,hWnd);
AfxBeginThread(Thread_Proc2,hWnd);
AfxBeginThread(Thread_Proc3,hWnd);

这样当Thread_Proc1Thread_Proc2占用信号量之后,只有等其中一个释放信号量之后,Thread_Proc3方可占用信号量,达到了线程之间资源的保护,实现数据共享!

本文即本人在学习多任务多线程过程的手记,供大家参考,望能得到各位指点。

 //////////////////////////////////////////////////////////////////////////////  


任何一个发文章的作者都应该被尊重。
如果有错误,大家一起讨论修正,共同进步。 ( only2004 发表于 2006-5-11 16:36:00)
 
我真不明白.它的4篇文章至少有2,3篇都有错误,代码根本无法实现同步.竟然还能被选中进入知识库? ( greenjava 发表于
2005-7-11 13:03:00)
 
:-
)
感谢你教会了我使用
 CSemaphore

:-(
CSemaphore Semaphore(2,2);
信口雌黄

error C2059: syntax error : 'constant'
负责点好不
( windcao
发表于 2004-1-8 10:56:00)
 
我特讨厌有些人的说话方式,好像自己就特nb的那种,为什么看不到别人的优点和长处? ( BadChen 发表于
2003-8-24 11:31:00)
 
程序太烂了,你的线程根据就没有同步

void CSharedResource::AccessResource()
{
CSingleLock SingleLock(ptrSemaphore);
SingleLock.Lock();
/* ......
  
资源访问
*/
Sleep(1000);
}
你为了一个窗口访问一个资源用了Sleep(1000),如果我在弹出两个窗口后,等一秒钟,必有一个或两个资源释放,等三个窗口就出来了,所以这样是不行的。
你应该是在窗口中,这样操作。
CSingleLock SingleLock(Semaphore);
SingleLock.Lock()
::MessageBox(...);
SingleLock.Unlock();
( shewo
发表于 2003-8-18 11:11:00)
 
不错,谢谢!

有个小问题感到奇怪:为什么3个对话框弹出的顺序为213,而不是123 ( zxyin4 发表于 2003-7-9 14:16:00)

阅读(358) | 评论(0)


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

评论

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