简单锁: CSimpleLock, CAutoCritic
在<<Advanced Logging for all kind of applications>>中发现了简单锁, codeproject上很多文章都提到了这种锁, 实现思路基本相同. 用起来很简洁.
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; }工程文件包含关系:
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