experiment: 锁操作

简单锁: CSimpleLock, CAutoCritic

  在<<Advanced Logging for all kind of applications>>中发现了简单锁, codeproject上很多文章都提到了这种锁, 实现思路基本相同. 用起来很简洁.

original url:

Advanced Logging for all kind of applications

http://www.codeproject.com/KB/debug/alx_log.aspx


<2011_1006>

今天在日志类重构中用到了自动锁.

 original url from : http://www.codeproject.com/KB/threads/stkmutex.aspx?display=Mobile

A heap or shared memory based mutex pool manager


只用到了其中的自动锁.

修改后, 根据不同的日志 全路径名称生成不同的日志锁名. 保证操作每一个日志,都有唯一的一把日志锁~, 这种日志锁基于 CreateMutexW, 可以跨进程.

// srcSocketOPTServer.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <locale.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>

#include "socket/SocketCommServer.h"
#include "LOg/DebugLog.h"

CDebugLog * pDebugLog = NULL;

int _tmain(int argc, _TCHAR* argv[])
{
	_tsetlocale(LC_ALL, _T("Chinese_People's Republic of China.936"));
	pDebugLog = new CDebugLog(_T("c:\\SocketOPTServer.txt"));
	if(!pDebugLog)
	{
		_tprintf(_T("error : new CDebugLog\n"));
	}

	TRACE_CODE_INFO(pDebugLog, _T(">> _tmain"));
	/** 日志效果
	* <18:36:05><3768-428> <emo\program\mainprog\srcsocketoptserver\srcsocketoptserver\srcsocketoptserver.cpp><24> [wmain][>> _tmain]
	*/

	CSocketCommServer SockServer;

	if(S_OK != SoketEnvironmentBegin())
		goto END;

	if(!SockServer.Connect(_T("50000"), TRUE))
	{
		_tprintf(_T("服务器连接建立失败\n"));
		goto END;
	}

	do
	{
		_tprintf(_T("按'q'键退出程序\n"));
		Sleep(100);
	}while(_T('q') != getchar());

	SockServer.DisConnect();

END: 
	SoketEnvironmentEnd();
	if(pDebugLog)
	{
		delete pDebugLog;
		pDebugLog = NULL;
	}
	getchar();
	return 0;
}


/**
* @file DebugLog.h
* @brief 调试日志
*/

#ifndef __DEBUGLOG_H__
#define __DEBUGLOG_H__

#include <windows.h>

#ifndef tstring  
#ifdef _UNICODE  
#define tstring std::wstring  
#else  
#define tstring std::string  
#endif  
#endif  

#ifndef WIDEN2

#define WIDEN2(x)       L ## x
#define WIDEN(x)        WIDEN2(x)
#define __WFILE__       WIDEN(__FILE__)
#define __WLINE__       __LINE__
#define __WFUNCTION__   WIDEN(__FUNCTION__)
#define TRACE_CODE_INFO(pDebugLog, strMsg) \
{\
tstring strFun = __WFUNCTION__;\
tstring strPathName = __WFILE__;\
if(strPathName.size() > 80)\
{\
	strPathName = strPathName.substr(strPathName.size() - 1 - 80, strPathName.size() - 1);\
}\
pDebugLog->logv(_T("<%s><%d> [%s][%s]\n"), strPathName.c_str(), __WLINE__, strFun.c_str(), strMsg);\
}

#endif /**< #ifndef WIDEN2 */

#define G_SIZE_LOG_BUF (INT)4096

#include "Locker/SysMutex.h"

class STK::CSysMutex;
class CDebugLog
{
public:
    CDebugLog(CONST TCHAR * pLogPathName);
    virtual ~CDebugLog();

	VOID logv(TCHAR * szFormat, ...);
	VOID log(TCHAR * pPathName, TCHAR * szFormat);

private:
    VOID InitLock();
    VOID UnInitLock();
	INT CreateLogFileIfNotExsit(TCHAR * pPathName);

private:
	STK::CSysMutex* m_pSysMutexLog;
	TCHAR m_cLogPathName[_MAX_PATH];
	TCHAR m_cLockerName[20 + 1];
};

#endif /**< #define __DEBUGLOG_H__ */

/**
* @file DebugLog.cpp
* @brief 调试日志实现
*/

#include "stdafx.h"

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <crtdbg.h>
#include <stdarg.h> /**< for va_list */

#include <string>
#include <list>

#include "DebugLog.h"
#include "Locker/AutoLock.h"

#include "openssl/sha.h"
#pragma comment(lib, "libeay32.lib")
#pragma comment(lib, "ssleay32.lib")

class CAutoLock;
CDebugLog::CDebugLog(CONST TCHAR * pLogPathName)
{
	ZeroMemory(m_cLogPathName, sizeof(m_cLogPathName));
	ZeroMemory(m_cLockerName, sizeof(m_cLockerName));

	_tcscpy_s(m_cLogPathName, sizeof(m_cLogPathName) / sizeof(TCHAR), pLogPathName);

	/** 根据日志全路径生成唯一的锁名称, 保证操作每一个日志文件都有一把相同的锁 */
	SHA1((const unsigned char *)m_cLogPathName, 
		sizeof(m_cLogPathName) / sizeof(TCHAR), 
		(unsigned char *)m_cLockerName);

	m_pSysMutexLog = NULL;

	InitLock();
}

CDebugLog::~CDebugLog()
{
	UnInitLock();
}

VOID CDebugLog::InitLock()
{
	if(!m_pSysMutexLog)
	{
		m_pSysMutexLog = new (std::nothrow) STK::CSysMutex(FALSE, m_cLockerName , NULL);
	}
}

VOID CDebugLog::UnInitLock()
{
	if(m_pSysMutexLog)
	{
		m_pSysMutexLog->Unlock();

		/** Free the system mutex */
		delete m_pSysMutexLog;
		m_pSysMutexLog = NULL;
	}
}

INT CDebugLog::CreateLogFileIfNotExsit(TCHAR * pPathName)
{
	errno_t err = 0;
	FILE * pFile = NULL;
	HANDLE hFind = INVALID_HANDLE_VALUE;
	WIN32_FIND_DATA FindFileData;

	STK::CAutoLock<STK::CSysMutex> lockAuto(m_pSysMutexLog);

	hFind = ::FindFirstFile(pPathName, &FindFileData);
	if(INVALID_HANDLE_VALUE == hFind)
	{
		/** not find log file, create it */
		err = _tfopen_s(&pFile, pPathName, _T("wb"));
		_ASSERT(0 == err);

		if(pFile)
		{
			fclose(pFile);
			pFile = NULL;
		}
	}

	return S_OK;
}

VOID CDebugLog::logv(TCHAR * szFormat, ...)
{
	STK::CAutoLock<STK::CSysMutex> lockAuto(m_pSysMutexLog);

	va_list args;
	va_start(args, szFormat);

	TCHAR * pBufMsg = new TCHAR[G_SIZE_LOG_BUF];
	_ASSERT(pBufMsg);
	ZeroMemory(pBufMsg, G_SIZE_LOG_BUF * sizeof(TCHAR));

	int nRc = 0;
	nRc = _vsntprintf_s(pBufMsg, G_SIZE_LOG_BUF, _TRUNCATE, szFormat, args);
	_ASSERT(G_SIZE_LOG_BUF > nRc);
	va_end(args);

	log(m_cLogPathName, pBufMsg);

	delete pBufMsg;
	pBufMsg = NULL;
}

VOID CDebugLog::log(TCHAR * pPathName, TCHAR * szFormat)
{
	errno_t err = 0;
	FILE * pFile = NULL;
	SYSTEMTIME tm;
	TCHAR * pBufMsg = new TCHAR[G_SIZE_LOG_BUF];
	_ASSERT(pBufMsg);
	ZeroMemory(pBufMsg, G_SIZE_LOG_BUF * sizeof(TCHAR));

	err = _tfopen_s(&pFile, pPathName, _T("ab+"));
	_ASSERT(0 == err);

	if(pFile)
	{
		::GetLocalTime(&tm);
		_stprintf_s(pBufMsg, G_SIZE_LOG_BUF, _T("<%2.2d:%2.2d:%2.2d><%d-%d> %s\r\n"),
			tm.wHour, tm.wMinute, tm.wSecond, 
			::GetCurrentProcessId(), ::GetCurrentThreadId(),
			szFormat);

		fwrite(pBufMsg, sizeof(TCHAR), _tcslen(pBufMsg), pFile);

		fclose(pFile);
		pFile = NULL;
	}

	if(pBufMsg)
	{
		delete pBufMsg;
		pBufMsg = NULL;
	}
}

#pragma once

/**
* original from : http://www.codeproject.com/KB/threads/stkmutex.aspx?display=Mobile
*/

#include <windows.h>

namespace STK
{
class CSysMutex
{
public:
	CSysMutex(bool bInitiallyOwn = false, 
              TCHAR * pszName = NULL,
		      LPSECURITY_ATTRIBUTES lpsaAttribute = NULL);
   	virtual ~CSysMutex();

public:
    bool Lock(DWORD dwTime);
	bool Unlock();

private:
    bool Create(bool bInitiallyOwn = false, 
                TCHAR * pszName = NULL,
		        LPSECURITY_ATTRIBUTES lpsaAttribute = NULL);

    bool Release();

private:
    HANDLE m_hMutex;
};
}

#include "stdafx.h"
#include "SysMutex.h"

namespace STK
{
CSysMutex::CSysMutex(bool bInitiallyOwn, TCHAR * pszName, LPSECURITY_ATTRIBUTES lpsaAttribute)
    : m_hMutex(NULL)
{
    Create(bInitiallyOwn, pszName, lpsaAttribute);
}

CSysMutex::~CSysMutex()
{
    Release();
}

bool CSysMutex::Unlock()
{
    if (m_hMutex == NULL)
    {
        return false;
    }

	return (::ReleaseMutex(m_hMutex) == TRUE);
}

bool CSysMutex::Lock(DWORD dwTimeout)
{
    if (m_hMutex == NULL)
    {
        return false;
    }

	DWORD dwRet = ::WaitForSingleObject(m_hMutex, dwTimeout);
	if ((dwRet == WAIT_OBJECT_0) || 
        (dwRet == WAIT_ABANDONED))
    {
		return true;
    }
	else
    {
		return false;
    }
}

bool CSysMutex::Create(bool bInitiallyOwn, TCHAR * pszName, LPSECURITY_ATTRIBUTES lpsaAttribute)
{
    Release();
	m_hMutex = ::CreateMutexW(lpsaAttribute, bInitiallyOwn, pszName);
    if (m_hMutex == NULL)
    {
        return false;
    }

    return true;
}

bool CSysMutex::Release()
{
    BOOL bRet = TRUE;
	if (m_hMutex != NULL)
	{
		bRet = ::CloseHandle(m_hMutex);
		m_hMutex = NULL;
	}

    return (bRet == TRUE);
}
}

#pragma once

#include <windows.h>
#include <iostream>
#include <string>
#include <list>

namespace STK
{
template <class T> 
class CAutoLock
{
public:
    CAutoLock(T *pLock)
    {
        if (pLock)
        {
            m_pLock = pLock;
            m_pLock->Lock(INFINITE);    
        }
    }

    virtual ~CAutoLock()
    {
        if (m_pLock)
        {
            m_pLock->Unlock();    
            m_pLock = NULL;
        }
    }

private:
    T* m_pLock;
};
}


整理了CDebugLog的用法

/**
* @file srcLockerOnLogOpt.cpp
* @brief environment: vs2005 + unicode + winxpSp3 + openssl
* @note 演示了在日志操作中使用自动锁, 演示了如何使每个日志文件对应与一把自动锁
*/

#include "stdafx.h"
#include <locale.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>

#include "Log/DebugLog.h"

CDebugLog * pDebugLog = NULL;

int _tmain(int argc, _TCHAR* argv[])
{
	_tsetlocale(LC_ALL, _T("Chinese_People's Republic of China.936"));
	pDebugLog = new CDebugLog(_T("c:\\LockerOnLogOpt.txt"));
	if(!pDebugLog)
	{
		_tprintf(_T("error : new CDebugLog\n"));
		goto END;
	}

	_tprintf(_T("ready log some thing\n"));
	TRACE_CODE_INFO(pDebugLog, _T(">> _tmain"));
	_tprintf(_T("log end\n"));

	/** log other log after pDebugLog is NOT NULL */

END:
	if(pDebugLog)
	{
		delete pDebugLog;
		pDebugLog = NULL;
	}

	_tprintf(_T("press any to quit\n"));
	getchar();

	/** 运行效果
	* ready log some thing
	* log end
	* press any to quit
	*/

	/** 日志效果
	* <19:11:11><3932-2320> <logopt\program\mainprog\srclockeronlogopt\srclockeronlogopt\srclockeronlogopt.cpp><28> [wmain][>> _tmain]
	*/
	return 0;
}

工程文件包含关系:

experiment: 锁操作_第1张图片

demo upload : srcLockerOnLogOpt_V2011_1006_2019.rar


<2011_1119>

线程锁的Demo

// srcThreadLocker.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <string>
#include <process.h>
#include "ThreadLocker/ls_threadlock.h"

void ThreadFn_Worker(PVOID pParam);
void ThreadFn_CheckKey(PVOID pParam);

BOOL bStop;

int _tmain(int argc, _TCHAR* argv[])
{
	bStop = FALSE;
	CLsMutex Mutex;

	_beginthread(ThreadFn_Worker, 0, &Mutex);
	_beginthread(ThreadFn_Worker, 0, &Mutex);
	_beginthread(ThreadFn_Worker, 0, &Mutex);
	_beginthread(ThreadFn_CheckKey, 0, NULL);

	while(!bStop)
	{
		Sleep(100);
	}

	_tprintf(_T("END, press any key to quit\n"));

	/**
	<ThreadFn_Worker>=<0x9CC>
	<ThreadFn_Worker>=<0x99C>
	<ThreadFn_Worker>=<0x358>
	<ThreadFn_Worker>=<0x9CC>

	Stop Command Happen
	<Quit ThreadFn_Worker[0x9CC]
	<ThreadFn_Worker>=<0x99C>
	<Quit ThreadFn_Worker[0x99C]
	<ThreadFn_Worker>=<0x358>
	<Quit ThreadFn_Worker[0x358]
	END, press any key to quit
	*/

	getchar();
	return 0;
}

void ThreadFn_Worker(PVOID pParam)
{
	CLsMutex * pMutex = (CLsMutex *)pParam;
	DWORD dwThreadId = GetCurrentThreadId();

	if(!pMutex)
	{
		goto END;
	}

	while(!bStop)
	{
		CLsThreadLock ThreadLock(pMutex);
		_tprintf(_T("<%s>=<0x%X>\n"), _T("ThreadFn_Worker"), dwThreadId);

		Sleep(10);
	}

END:
	_tprintf(_T("<%s[0x%X]\n"), _T("Quit ThreadFn_Worker"), dwThreadId);
}

void ThreadFn_CheckKey(PVOID pParam)
{
	getchar();
	bStop = TRUE;

	_tprintf(_T("Stop Command Happen\n"));
}
src demo: srcThreadLocker_V2011_1119_0240.rar


你可能感兴趣的:(File,null,delete,Class,logging,attributes)