秒杀多线程第十篇 读者写者问题

下面利用信号量和互斥量来做一个读写锁类,代码如下:

//
//读写锁
功能:该类为多线程做对资源的读写锁,其中信号量用来读写互斥和写写互斥,互斥量用来读读互斥
思路概要:看代码中的注释可知
//
#include "StdAfx.h"
#include "RWLock.h"
//

#ifndef FALSE 
#define FALSE 0
#endif

#ifndef TRUE
#define TRUE 1
#endif

//完成读写锁初始化
CRWLock::CRWLock()
{

	InitRWLock();
	
}

//
CRWLock::~CRWLock()
{
	DestroyRWLock();
}

BOOL  CRWLock::MyWaitForSingleObject(HANDLE hObject)
{
#ifdef WIN32

	DWORD result;

	result = WaitForSingleObject(hObject, INFINITE);

	return (result == WAIT_OBJECT_0);

#endif
}

BOOL  CRWLock::InitRWLock()
{
#ifdef WIN32

	m_RWLock.nReaderCount = 0;
	m_RWLock.hDataLock = CreateSemaphore(NULL, 1, 1, NULL);//初始化创建信号量,在信号量的介绍中有对其参数的解释,此处不多做介绍,
	//这里初始化资源个数为1,如果先做读操作请求的话,及时没有先写也会请求成功,个人觉得改为0比较好
	if (m_RWLock.hDataLock == NULL)
	{
		return FALSE;
	}

	m_RWLock.hMutex = CreateMutex(NULL, FALSE, NULL);//第二个参数为false,表明互斥量不为任何线程占用,处于触发状态。
	if (m_RWLock.hMutex == NULL)
	{
		CloseHandle(m_RWLock.hDataLock);
		return FALSE;
	}

	return TRUE;

#else

	 pthread_rwlock_init(&m_RWLock, NULL);

	 return TRUE;
#endif

}

BOOL  CRWLock::DestroyRWLock()
{
#ifdef WIN32

	DWORD result = WaitForSingleObject(m_RWLock.hDataLock, INFINITE);
	if (result != WAIT_OBJECT_0)
	{
		return FALSE;
	}

	CloseHandle(m_RWLock.hMutex);
	CloseHandle(m_RWLock.hDataLock);
	return TRUE;

#else

	pthread_rwlock_destroy(&m_RWLock);

	return TRUE;

#endif
}

BOOL CRWLock::AcquireReadLock()//请求读操作
{
	BOOL result = TRUE;

#ifdef WIN32

	if (MyWaitForSingleObject(m_RWLock.hMutex) == FALSE)//阻塞等待互斥量m_RWLock.hMutex被触发
	{
		return FALSE;
	}

	m_RWLock.nReaderCount ++;
	if(m_RWLock.nReaderCount == 1)
	{
		result = MyWaitForSingleObject(m_RWLock.hDataLock);//当是第一个读的时候,阻塞等待信号量计数大于0,即做过写操作有数据可读,然后对信号量--,
	}

    /***此处做读操作***/

	ReleaseMutex(m_RWLock.hMutex);//触发互斥量

	return result;

#else
	pthread_rwlock_rdlock(&m_RWLock);

	return result;
#endif
}


BOOL CRWLock::ReleaseReadLock()
{
	int result = TRUE;

#ifdef WIN32

	LONG lPrevCount;

	if (MyWaitForSingleObject(m_RWLock.hMutex) == FALSE)//阻塞等待互斥量m_RWLock.hMutex被触发
	{
		return FALSE;
	}

	--m_RWLock.nReaderCount;

	if (m_RWLock.nReaderCount == 0)
	{
		result = ReleaseSemaphore(m_RWLock.hDataLock, 1, &lPrevCount);//如果为最后一个读者则信号量++,通知其他线程没有线程在做读操作,此时可以做写操作了
	}

	ReleaseMutex(m_RWLock.hMutex);//触发互斥量,来通知此次读操作以完成,其他线程可做读操作

	return result;
#else

	return pthread_rwlock_unlock(&m_RWLock);	

#endif
}

BOOL CRWLock::AcquireWriteLock()
{

#ifdef WIN32

	return MyWaitForSingleObject(m_RWLock.hDataLock);//可理解为等待信号量被触发,来源为ReleaseWriteLock中触发(即写操作以完成)或145行的读操作以完成

#else
	
	return pthread_rwlock_wrlock(&m_RWLock);

#endif
}


BOOL CRWLock::ReleaseWriteLock()
{
#ifdef WIN32

	int result = TRUE;
	LONG lPrevCount;

	result = ReleaseSemaphore(m_RWLock.hDataLock, 1, &lPrevCount);//信号量++,来通知其他线程本次写操作以完成,可以做读操作或写操作了
	if (lPrevCount != 0)
	{
		return FALSE;
	}

	return result;

#else
	return  pthread_rwlock_unlock(&m_RWLock);
#endif
}
//
//读写锁

//
#ifndef  _RWMETUX_H_
#define  _RWMETUX_H_

//
#ifndef  WIN32
  #include 
   
   
    
    
#endif

//
// 多证书链读写锁类
#ifdef  WIN32

typedef struct _RWLock
{
	HANDLE	hMutex;    
	HANDLE	hDataLock;
	int		nReaderCount;
} RWLock;

#endif

class  CRWLock
{
public:
	CRWLock();
	~CRWLock();

	BOOL  AcquireReadLock(void);    //请求读操作锁,请求不成功则阻塞
	BOOL  ReleaseReadLock(void);    //释放读操作锁

	BOOL  AcquireWriteLock(void);   //请求写操作锁,请求不成功则阻塞
	BOOL  ReleaseWriteLock(void);   //释放写操作锁

private:
	BOOL  CRWLock::MyWaitForSingleObject(HANDLE hObject);
	BOOL  CRWLock::InitRWLock();
	BOOL  CRWLock::DestroyRWLock();
private:

#ifdef  WIN32
	RWLock	m_RWLock;   //读写锁
#else
	pthread_rwlock_t m_RWLock;
#endif
	
};

#endif   //_RWMETUX_H_

   
   

看了一下我转载的这些文章的作者写的秒杀多线程第十一篇 读者写者问题  这个对读写锁操作的列子,是存在问题的。第十一篇中的评论:“确实有这个问题存在。 g_hEventNoReader = CreateEvent(NULL, FALSE, TRUE, NULL); 这句使得写线程一开始就得到 WaitForSingleObject(g_hEventNoReader, INFINITE)成功执行的机会,如果在读线程对 g_nReaderCount进行修改之前让读线程Sleep(),则会出现既在读又在写的情况。”这个是存在的,导致这个的原因主要是 g_hEventWriter = CreateEvent(NULL, TRUE, TRUE, NULL); 第二个参数他设置为TRUE导致WaitForSingleObject不会把事件设置为未触发状态,而此时读线程也可以继续执行,导致读写的恶性竞争。其次第十四篇中秒杀多线程第十四篇 读者写者问题继 读写锁SRWLock  由于用到了SRWLock所以解决了这个问题,这个读写锁内部做了相应的操作吧!在此贴出这为大神的代码:

//读者与写者问题继 读写锁SRWLock
#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
//设置控制台输出颜色
BOOL SetConsoleColor(WORD wAttributes)
{
	HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
	if (hConsole == INVALID_HANDLE_VALUE)
		return FALSE;
	return SetConsoleTextAttribute(hConsole, wAttributes);
}
const int READER_NUM = 5;  //读者个数
//关键段和事件
CRITICAL_SECTION g_cs;
SRWLOCK          g_srwLock; 
//读者线程输出函数(变参函数的实现)
void ReaderPrintf(char *pszFormat, ...)
{
	va_list   pArgList;
	va_start(pArgList, pszFormat);
	EnterCriticalSection(&g_cs);
	vfprintf(stdout, pszFormat, pArgList);
	LeaveCriticalSection(&g_cs);
	va_end(pArgList);
}
//读者线程函数
unsigned int __stdcall ReaderThreadFun(PVOID pM)
{
	ReaderPrintf("     编号为%d的读者进入等待中...\n", GetCurrentThreadId());
	//读者申请读取文件
	AcquireSRWLockShared(&g_srwLock);

	//读取文件
	ReaderPrintf("编号为%d的读者开始读取文件...\n", GetCurrentThreadId());
	Sleep(rand() % 100);
	ReaderPrintf(" 编号为%d的读者结束读取文件\n", GetCurrentThreadId());

	//读者结束读取文件
	ReleaseSRWLockShared(&g_srwLock);
	return 0;
}
//写者线程输出函数
void WriterPrintf(char *pszStr)
{
	EnterCriticalSection(&g_cs);
	SetConsoleColor(FOREGROUND_GREEN);
	printf("     %s\n", pszStr);
	SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
	LeaveCriticalSection(&g_cs);
}
//写者线程函数
unsigned int __stdcall WriterThreadFun(PVOID pM)
{
	WriterPrintf("写者线程进入等待中...");
	//写者申请写文件
	AcquireSRWLockExclusive(&g_srwLock);
		
	//写文件
	WriterPrintf("  写者开始写文件.....");
	Sleep(rand() % 100);
	WriterPrintf("  写者结束写文件");

	//标记写者结束写文件
	ReleaseSRWLockExclusive(&g_srwLock);
	return 0;
}
int main()
{
	printf("  读者写者问题继 读写锁SRWLock\n");
	printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");

	//初始化读写锁和关键段
	InitializeCriticalSection(&g_cs);
	InitializeSRWLock(&g_srwLock);

	HANDLE hThread[READER_NUM + 1];
	int i;
	//先启动二个读者线程
	for (i = 1; i <= 2; i++)
		hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);
	//启动写者线程
	hThread[0] = (HANDLE)_beginthreadex(NULL, 0, WriterThreadFun, NULL, 0, NULL);
	Sleep(50);
	//最后启动其它读者结程
	for ( ; i <= READER_NUM; i++)
		hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);
	WaitForMultipleObjects(READER_NUM + 1, hThread, TRUE, INFINITE);
	for (i = 0; i < READER_NUM + 1; i++)
		CloseHandle(hThread[i]);

	//销毁关键段
	DeleteCriticalSection(&g_cs);
	return 0;
}
     
     
    
    
   
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值