windows下共享内存和数据同步
前言
当在windows系统下,有多个exe程序同时频繁处理大量文件操作时,而且还要保证效率,假设一个简单的场景:一个程序负责产生数据,另一个程序负责读取数据,那么问题来了,两个进程都是彼此独立的,彼此都不知道各自的存在,如何读取数据呢?我们首先能想到的是使用共享内存。但是,在多核情况下,读写如何同步呢?试想以下场景:
场景1:出现A进程数据写了一部分数据在共享内存中(没写完),而这时B进程读这块内存,那么读取的这块内存数据就不完整。
场景2:当A进程完整的把一整包数据写到内存中,而这时B进程在处理其他的事情,来不及读这块内存。而这时B进程有写了第二包包数据到内存中(把先前的数据冲掉了),B进程忙完了手头上的事情,来读这块内存数据,B进程将会丢掉第一包数据。
解决思路
第一种方案:加标志位来保证数据安全。把标志位封装到数据头,当A进程写数据时先把标志位置1(写数据中),这时B进程想读数据,发现数据头标志位是1,等待,直到数据头标志位为1才读取。
第二种方案:使用文件锁,线程A写数据,具有独占锁属性,线程B没有权限读取内存文件。详见微软官方LockFile函数文档:LockFile()第三种方案:加互斥锁
尝试
第一种方案:加标志位,如果是单核、单线程的状态下,在进程间、或线程间同步不会有问题,但是遇到多核、多线程的情况下,在极端情况下,比如写进程刚写了数据,标志位还没来得及修改,这时读进程获取的标志位就是有问题的,可能就会读到错误的数据。
遇到的问题
代码
服务器端
服务端头文件
/******************************************************************
++ File Name : FFMClass.h
++ Description: 共享内存类
---------------------------------------------------------------
++ Author: Fei ZhaoDong
++ Create time: 2004/3/25 上午 10:00:00
++ Version: 1.1
++ Modifier:
++ Activities:
++ Update List: 2004/3/30 下午 02:59:45
*******************************************************************/
// FFMClass.h: interface for the CFFMClass.
//
//
//#include <Winbase.h>
using namespace std;
//
// Macro definition
// 以下为共享内存定义
// 默认的文件名
//_FZD_MAP_" // 默认的共享内存名
// 默认的共享内存大小:200兆
const DWORD NETRGUSER_CFM_CODE = 0x1211DBFF; // 校验码, 用于命令数据
const DWORD NETRGUSER_CMD_NONE = 0; // 初始化指令码, 无指令
// 以下为错误码定义
// 错误描述长度
// 已经存在完全一样的共享内存
// 未分配共享内存文件
// 校验码不匹配
//
// 内存文件格式定义
// 用于存储命令数据的内存文件格式
typedef struct _tagDATA_HEADER
{
DWORD dwConfirmCode; // 校验码
DWORD nCommandCode; // 指令识别码
DWORD dwDataSize; // 数据的大小
BYTE dwReserved[32]; // 保留 读写标志位,
BYTE dwElapsed[64]; //时间戳
BYTE bInfo[1]; // 数据起始地址
_tagDATA_HEADER()
{
dwConfirmCode = NETRGUSER_CFM_CODE;
nCommandCode = NETRGUSER_CMD_NONE;
dwDataSize = 0;
ZeroMemory(dwReserved, 19);
ZeroMemory(bInfo, 1);
}
} DATA_HEADER, *LPDATA_HEADER;
typedef DWORD(WINAPI* PSetEntriesInAcl)(ULONG, PEXPLICIT_ACCESS, PACL, PACL*);
// 用于存储应答数据的共享内存文件格式 (暂不用)
typedef struct _tagANS_HEADER
{
} ANS_HEADER, *LPANS_HEADER;
//
// 类定义,共享内存服务端
class CFFMServer
{
public:
CFFMServer();
virtual ~CFFMServer();
CFFMServer(char* szFileName, char* szMapName, DWORD dwSize);
protected:
PSetEntriesInAcl m_fnpSetEntriesInAcl;
HANDLE m_hFile; // 映射文件句柄
HANDLE m_hFileMap; // 内存文件句柄
LPVOID m_lpFileMapBuffer; // 缓冲区指针
char* m_pFileName; // 映射文件名
char* m_pMapName; // 内存文件名
DWORD m_dwSize; // 缓冲区大小
BOOL m_bCreateFlag; // 是否已创建共享内存
DWORD m_dwLastError; // 错误代码
BOOL m_bRetLockFile; //文件锁标志
LPCTSTR m_lpMutexName; //互斥量名字
HANDLE m_hMutex; //互斥量,独占锁
HANDLE m_hSemaphore;//信号量,
mutable std::shared_mutex m_mutex;
std::shared_lock<std::shared_mutex> m_readLock;
std::unique_lock<std::shared_mutex> m_writeLock;
//三组共享内存
HANDLE m_hFileArr[3];// 映射文件句柄数组
HANDLE m_hFileMapArr[3]; // 内存文件句柄数组
//计算时间
ElapsedTimer m_elspsedTimer;
private:
void _Init(); // 初始化参数
BOOL _IsWinNTLater(); // 判断当前操作系统
public:
BOOL Create(char* szFileName = DEFAULT_FILENAME,
char* szMapName = DEFAULT_MAPNAME,
DWORD dwSize = DEFAULT_MAPSIZE); // 新建共享内存
LPVOID GetBuffer(); // 获取内存文件指针
DWORD GetSize(); // 获取内存文件大小
void Destory(); // 销毁已有的共享内存
BOOL WriteCmdData( // 写入命令数据
DWORD nCommandCode,
DWORD dwDataSize,
const LPVOID pBuf);
BOOL CanWrite();
BOOL WriteOver();
};
// FZD_FFMCLASS_H
服务端实现文件
/******************************************************************
++ File Name : FFMClass.cpp
++ Description: 共享内存类
---------------------------------------------------------------
++ Author: Fei ZhaoDong
++ Create time: 2004/3/25 上午 10:00:00
++ Version: 1.0
++ Modifier:
++ Activities:
++ Update List: 2004/3/29 下午 02:59:45
*******************************************************************/
// FFMClass.cpp: implementation of the CFFMClass.
//
//
//#include <aclapi.h>
//#include <windows.h>
//#include <aclapi.h>
//#include <lmerr.h>
//
//#include <stdio.h>
//
// CFFMServer
//
using namespace std;
char SemaphoreName[50] = "lockShardMemory";
CFFMServer::CFFMServer()
{
m_dwLastError = 0;
m_fnpSetEntriesInAcl = NULL;
_Init();
}
CFFMServer::~CFFMServer()
{
Destory();
}
CFFMServer::CFFMServer(char* szFileName, char* szMapName, DWORD dwSize)
{
// 以自定义设置创建共享内存块
_Init();
Create(szFileName, szMapName, dwSize);
}
// 初始化各个参数
void CFFMServer::_Init()
{
m_hFile = NULL;
m_hFileMap = NULL;
m_lpFileMapBuffer = NULL;
m_pFileName = NULL;
m_pMapName = NULL;
m_dwSize = 0;
m_bCreateFlag = FALSE;
m_lpMutexName = "fileLock";
}
// 判断是否NT4.0以上操作系统
BOOL CFFMServer::_IsWinNTLater()
{
return FALSE;
OSVERSIONINFO Ver;
BOOL bAbleVersion = FALSE;
Ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if(GetVersionExA(&Ver))
{
if(Ver.dwPlatformId == VER_PLATFORM_WIN32_NT
&& Ver.dwMajorVersion >= 4)
{
bAbleVersion = TRUE;
}
}
else
{
m_dwLastError = GetLastError();
}
return bAbleVersion;
}
// 释放当前共享内存,并重新初始化参数
void CFFMServer::Destory()
{
if(m_lpFileMapBuffer != NULL)
{
UnmapViewOfFile(m_lpFileMapBuffer);
m_lpFileMapBuffer = NULL;
}
if(m_hFileMap != NULL)
{
CloseHandle(m_hFileMap);
m_hFileMap = NULL;
}
if(m_hFile && m_hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hFile);
m_hFile = NULL;
}
if(m_pFileName != NULL)
{
free(m_pFileName);
m_pFileName = NULL;
}
if(m_pMapName != NULL)
{
free(m_pMapName);
m_pMapName = NULL;
}
_Init();
}
static void FreeSidEx(PSID oSID)
{
try
{
FreeSid(oSID);
}
catch(...)
{
}
}
// 创建共享内存块
BOOL CFFMServer::Create(char* szFileName, char* szMapName, DWORD dwSize)
{
// 释放已有的共享内存块
if(m_bCreateFlag)
{
Destory();
}
// 拷贝各个参数
if(szFileName)
{
m_pFileName = _strdup(szFileName);
}
if(szMapName)
{
m_pMapName = _strdup(szMapName);
}
else
{
m_pMapName = _strdup(DEFAULT_MAPNAME);
}
if(dwSize > 0)
{
m_dwSize = dwSize;
}
else
{
m_dwSize = DEFAULT_MAPSIZE;
}
// 以下创建共享内存
if(m_pFileName)
{
m_hFile = CreateFile(
m_pFileName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
}
else
{
// 默认情况下,在页面文件中创建共享内存
m_hFile = INVALID_HANDLE_VALUE;
}
if(_IsWinNTLater())
{
// Set DACL
const int NUM_ACES = 2; // number if ACEs int DACL
// evryone -- read
// creator -- full access
// 初始化参数
PSID pEveryoneSID = NULL; // everyone群组SID
PSID pCreatorSID = NULL; // creator群组SID
PACL pFileMapACL = NULL; // 准备新内存文件的DACL
PSECURITY_DESCRIPTOR pSD = NULL; // 内存文件的SD
SECURITY_ATTRIBUTES saFileMap; // 内存文件的SA
EXPLICIT_ACCESS ea[NUM_ACES]; // 外部访问结构
BOOL bHasErr = FALSE; // 返回值
// 以下创建SID
SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
SID_IDENTIFIER_AUTHORITY SIDAuthCreator = SECURITY_CREATOR_SID_AUTHORITY;
// Evryone
if(!AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0, &pEveryoneSID))
{
bHasErr = TRUE;
goto Finish;
}
// Creator
if(!AllocateAndInitializeSid(&SIDAuthCreator, 1, SECURITY_CREATOR_OWNER_RID,
0, 0, 0, 0, 0, 0, 0, &pCreatorSID))
{
bHasErr = TRUE;
goto Finish;
}
// 填充ACE
ZeroMemory(&ea, NUM_ACES * sizeof(EXPLICIT_ACCESS));
// S-1-1-0 evryone, 唯读权限
ea[0].grfAccessPermissions = GENERIC_READ | GENERIC_WRITE;
ea[0].grfAccessMode = SET_ACCESS;
ea[0].grfInheritance = NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea[0].Trustee.ptstrName = (LPTSTR)pEveryoneSID;
// S-1-3-0 creator owner, 完全权限
ea[1].grfAccessPermissions = STANDARD_RIGHTS_ALL;
ea[1].grfAccessMode = SET_ACCESS;
ea[1].grfInheritance = NO_INHERITANCE;
ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea[1].Trustee.ptstrName = (LPTSTR)pCreatorSID;
// 创建并填充ACL
if(NULL == m_fnpSetEntriesInAcl)
{
HINSTANCE hLib = ::LoadLibrary("Advapi32.dll");
if(NULL != hLib)
{
m_fnpSetEntriesInAcl = (PSetEntriesInAcl)GetProcAddress(hLib, "SetEntriesInAclA");
::FreeLibrary(hLib);
hLib = NULL;
}
}
if(ERROR_SUCCESS != m_fnpSetEntriesInAcl(NUM_ACES, ea, NULL, &pFileMapACL))
{
bHasErr = TRUE;
goto Finish;
}
// 创建并初始化SD
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if(NULL == pSD)
{
bHasErr = TRUE;
goto Finish;
}
if(!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
{
bHasErr = TRUE;
goto Finish;
}
// 添加ACL到SD中去
if(!SetSecurityDescriptorDacl(pSD,
TRUE, // fDaclPresent flag
pFileMapACL,
FALSE)) // not a default DACL
{
bHasErr = TRUE;
goto Finish;
}
// 设置SA
saFileMap.nLength = sizeof(SECURITY_ATTRIBUTES);
saFileMap.bInheritHandle = FALSE;
saFileMap.lpSecurityDescriptor = pSD;
// 创建共享内存文件
if(m_hFile != NULL)
{
m_hFileMap = CreateFileMapping(
m_hFile,
&saFileMap,
PAGE_READWRITE,
0,
m_dwSize,
m_pMapName);
if(NULL == m_hFileMap)
{
m_hFileMap = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE,
TRUE, m_pMapName);
if(NULL == m_hFileMap)
{
m_dwLastError = GetLastError();
Destory();
goto Finish;
}
}
}
Finish:
//if (pSD != NULL)
//{
// LocalFree(pSD);
//}
pSD = NULL;
if(pFileMapACL != NULL)
{
LocalFree(pFileMapACL);
pFileMapACL = NULL;
}
if(pEveryoneSID != NULL)
{
FreeSidEx(pEveryoneSID);
pEveryoneSID = NULL;
}
if(pCreatorSID != NULL)
{
FreeSidEx(pCreatorSID);
pCreatorSID = NULL;
}
if(bHasErr)
{
m_dwLastError = GetLastError();
return FALSE;
}
}
else
{
// 创建共享内存文件
if(m_hFile)
{
m_hFileMap = CreateFileMapping(
m_hFile,
NULL,
PAGE_READWRITE,
0,
m_dwSize,
m_pMapName);
if(NULL == m_hFileMap)
{
m_dwLastError = GetLastError();
Destory();
return FALSE;
}
}
}
// 映射文件指针到用户
if(m_hFileMap)
{
m_lpFileMapBuffer = MapViewOfFile(
m_hFileMap,
FILE_MAP_ALL_ACCESS,
0,
0,
m_dwSize);
if(NULL == m_lpFileMapBuffer)
{
m_dwLastError = GetLastError();
Destory();
return FALSE;
}
ZeroMemory(GetBuffer(), GetSize());
}
m_bCreateFlag = TRUE;
return TRUE;
}
// 获取内存文件指针
LPVOID CFFMServer::GetBuffer()
{
return (m_lpFileMapBuffer) ? (m_lpFileMapBuffer) : (NULL);
}
// 获取内存文件大小
DWORD CFFMServer::GetSize()
{
//m_dwSize += 1000;
return m_dwSize;
}
BOOL CFFMServer::WriteCmdData(DWORD nCommandCode, DWORD dwDataSize, const LPVOID pBuf)
{
// 检验数据的合理性
if(NULL == GetBuffer())
{
m_dwLastError = ERROR_NO_MAPFILE;
SetLastError(ERROR_NO_MAPFILE);
return FALSE;
}
if(NETRGUSER_CMD_NONE == nCommandCode)
{
m_dwLastError = ERROR_INVALID_CMDCODE;
SetLastError(ERROR_INVALID_CMDCODE);
return FALSE;
}
if(dwDataSize > 0 && pBuf == NULL)
{
m_dwLastError = ERROR_INVALID_USER_BUFFER;
SetLastError(ERROR_INVALID_USER_BUFFER);
return FALSE;
}
if (dwDataSize + sizeof(DATA_HEADER) > GetSize())
{
m_dwLastError = ERROR_BUFFER_OVERFLOW;
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
// 填写数据结构
// 文件头
DATA_HEADER dataHeader;
int size = sizeof(DATA_HEADER);
dataHeader.nCommandCode = nCommandCode;
dataHeader.dwDataSize = dwDataSize;
计算时间
//clock_t benin, end;
//benin = clock();
//char szTime[32];
//long dTime = (long)benin;
//ZeroMemory(szTime, 32);
//sprintf(szTime, "%hd", dTime);
//memcpy(dataHeader.dwReserved, szTime, 32);
char szTime[64];
ZeroMemory(szTime, 64);
ElapsedTimer elapsed;
elapsed.reset();
int64_t timeStamp = elapsed.getTimeStamp();
//int64_t elspsedTime = m_elspsedTimer.elapsedMs(); //毫秒
_i64toa_s(timeStamp, szTime, TIME_BUFFER_SIZE, 10);
//sprintf(szTime, "%hd", timeStamp);
memcpy(dataHeader.dwElapsed, szTime, 64);
ZeroMemory(GetBuffer(), GetSize());
memcpy(GetBuffer(), &dataHeader, sizeof(DATA_HEADER));
// 数据块
LPDATA_HEADER pData = (LPDATA_HEADER)GetBuffer();
memcpy(pData->bInfo, pBuf, dwDataSize);
pData->dwReserved[0] = 1;
pData->dwReserved[1] = 1;
pData->dwReserved[2] = 1;
ElapsedTimer elapsedEnd;
int64_t endCount = elapsedEnd.getTimeStamp();
int64_t passTime = endCount - timeStamp;
double dTime = static_cast<double>(passTime);
return TRUE;
}
BOOL CFFMServer::CanWrite()
{
LPDATA_HEADER pData = (LPDATA_HEADER)GetBuffer();
bool ret = pData->dwReserved[0] == 0 &&
pData->dwReserved[1] == 0 &&
pData->dwReserved[2] == 0;
bool ret1 = pData->dwReserved[2] == 0;
return ret;
}
BOOL CFFMServer::WriteOver()
{
DATA_HEADER dataHeader;
int size = sizeof(DATA_HEADER);
dataHeader.nCommandCode = 1;
dataHeader.dwDataSize = 2;
ZeroMemory(GetBuffer(), GetSize());
dataHeader.dwReserved[5] = 10;
memcpy(GetBuffer(), &dataHeader, sizeof(DATA_HEADER));
return true;
}
客户端
客户端头文件
/******************************************************************
++ File Name : FFMClass.h
++ Description: 共享内存类
---------------------------------------------------------------
++ Author: Fei ZhaoDong
++ Create time: 2004/3/25 上午 10:00:00
++ Version: 1.1
++ Modifier:
++ Activities:
++ Update List: 2004/3/30 下午 02:59:45
*******************************************************************/
// FFMClass.h: interface for the CFFMClass.
//
//
//#include <Winbase.h>
//
// Macro definition
// 以下为共享内存定义
// 默认的文件名
//_FZD_MAP_" // 默认的共享内存名
// 默认的共享内存大小
const DWORD NETRGUSER_CFM_CODE = 0x1211DBFF; // 校验码, 用于命令数据
const DWORD NETRGUSER_CMD_NONE = 0; // 初始化指令码, 无指令
// 以下为错误码定义
// 错误描述长度
// 已经存在完全一样的共享内存
// 未分配共享内存文件
// 校验码不匹配
//
// 内存文件格式定义
// 用于存储命令数据的内存文件格式
typedef struct _tagDATA_HEADER
{
DWORD dwConfirmCode; // 校验码
DWORD nCommandCode; // 指令识别码
DWORD dwDataSize; // 数据的大小
BYTE dwReserved[19]; // 保留
BYTE bInfo[1]; // 数据起始地址
_tagDATA_HEADER()
{
dwConfirmCode = NETRGUSER_CFM_CODE;
nCommandCode = NETRGUSER_CMD_NONE;
dwDataSize = 0;
ZeroMemory(dwReserved, 19);
ZeroMemory(bInfo, 1);
}
} DATA_HEADER, *LPDATA_HEADER;
typedef DWORD(WINAPI* PSetEntriesInAcl)(ULONG, PEXPLICIT_ACCESS, PACL, PACL*);
// 用于存储应答数据的共享内存文件格式 (暂不用)
typedef struct _tagANS_HEADER
{
} ANS_HEADER, *LPANS_HEADER;
//
// 类定义,共享内存客户端
class CFFMClient
{
public:
CFFMClient();
virtual ~CFFMClient();
CFFMClient(DWORD dwAccess, char* szMapName, DWORD dwSize);
protected:
HANDLE m_hFileMap; // 内存文件句柄
LPVOID m_lpFileMapBuffer; // 内存文件指针
char* m_pMapName; // 内存文件名
DWORD m_dwSize; // 缓冲区大小
BOOL m_bOpenFlag; // 是否已经打开了一个内存文件
DWORD m_dwLastError; // 错误代码
private:
void _Init(); // 初始化参数
public:
BOOL Open(DWORD dwAccess = FILE_MAP_READ | FILE_MAP_WRITE,
char* szMapName = DEFAULT_MAPNAME,
DWORD dwSize = 0); // 打开一个内存文件
LPVOID GetBuffer(); // 获取当前内存文件的指针
void Destory(); // 关闭当前对内存文件的访问
DWORD GetSize(); // 获取内存文件大小
BOOL GetCmdDataSize(DWORD* pDataSize); // 读取命令数据大小
int ReadCmdData( // 读取命令数据
DWORD dwCommandCode,
DWORD dwBufSize,
LPVOID pOutBuf);
BOOL WriteCmdData( // 写入命令数据
DWORD memSize,
DWORD nCommandCode,
DWORD dwDataSize,
const LPVOID pBuf);
BOOL CanRead();
BOOL IsOver();
};
// FZD_FFMCLASS_H
在这里插入代码片
客服端实现文件
/******************************************************************
++ File Name : FFMClass.cpp
++ Description: 共享内存类
---------------------------------------------------------------
++ Author: Fei ZhaoDong
++ Create time: 2004/3/25 上午 10:00:00
++ Version: 1.0
++ Modifier:
++ Activities:
++ Update List: 2004/3/29 下午 02:59:45
*******************************************************************/
// FFMClass.cpp: implementation of the CFFMClass.
//
//
//#include <aclapi.h>
//#include <windows.h>
//#include <aclapi.h>
//#include <lmerr.h>
//
//#include <stdio.h>
//
// FFMClient
//
//
// CFFMClient
//
using namespace std;
char SemaphoreName[50] = "lockShardMemory";
CFFMClient::CFFMClient()
{
m_dwLastError = 0;
_Init();
}
CFFMClient::~CFFMClient()
{
Destory();
}
CFFMClient::CFFMClient(DWORD dwAccess, char* szMapName, DWORD dwSize)
{
_Init();
if(!Open(dwAccess, szMapName, dwSize))
{
Destory();
}
}
// 初始化参数
void CFFMClient::_Init()
{
m_hFileMap = NULL;
m_lpFileMapBuffer = NULL;
m_pMapName = NULL;
m_bOpenFlag = FALSE;
}
// 关闭当前对内存文件的访问
void CFFMClient::Destory()
{
if(m_lpFileMapBuffer)
{
UnmapViewOfFile(m_lpFileMapBuffer);
m_lpFileMapBuffer = NULL;
}
if(m_hFileMap)
{
CloseHandle(m_hFileMap);
m_hFileMap = NULL;
}
if(m_pMapName)
{
free(m_pMapName);
m_pMapName = NULL;
}
_Init();
}
// 打开一个内存文件
BOOL CFFMClient::Open(DWORD dwAccess, char* szMapName, DWORD dwSize)
{
if(m_bOpenFlag)
{
Destory();
}
if(szMapName != NULL)
{
m_pMapName = _strdup(szMapName);
}
else
{
m_pMapName = _strdup(DEFAULT_MAPNAME);
}
m_hFileMap = OpenFileMapping(dwAccess, TRUE, m_pMapName);
if(NULL == m_hFileMap)
{
m_dwLastError = GetLastError();
Destory();
return FALSE;
}
m_lpFileMapBuffer = MapViewOfFile(m_hFileMap, dwAccess, 0, 0, dwSize);
if(NULL == m_lpFileMapBuffer)
{
m_dwLastError = GetLastError();
Destory();
return FALSE;
}
m_bOpenFlag = TRUE;
return TRUE;
}
// 获取当前内存文件的指针
LPVOID CFFMClient::GetBuffer()
{
return (m_lpFileMapBuffer) ? (m_lpFileMapBuffer) : (NULL);
}
// 读取命令数据大小
BOOL CFFMClient::GetCmdDataSize(DWORD* pDataSize)
{
if(pDataSize == NULL)
{
return FALSE;
}
*pDataSize = 0;
LPDATA_HEADER pHeader = (LPDATA_HEADER)GetBuffer();
if(NULL == pHeader)
{
m_dwLastError = ERROR_NO_MAPFILE;
SetLastError(ERROR_NO_MAPFILE);
return FALSE;
}
if(NETRGUSER_CFM_CODE != pHeader->dwConfirmCode)
{
m_dwLastError = ERROR_INVALID_CFMCODE;
SetLastError(ERROR_INVALID_CFMCODE);
return FALSE;
}
if(NETRGUSER_CMD_NONE == pHeader->nCommandCode)
{
m_dwLastError = ERROR_INVALID_CMDCODE;
SetLastError(ERROR_INVALID_CMDCODE);
return FALSE;
}
*pDataSize = pHeader->dwDataSize;
return TRUE;
}
// 读取命令数据
int CFFMClient::ReadCmdData(DWORD dwCommandCode, DWORD dwBufSize, LPVOID pOutBuf)
{
if(pOutBuf == NULL)
{
return FALSE;
}
LPDATA_HEADER pHeader = (LPDATA_HEADER)GetBuffer();
if(NULL == pHeader)
{
m_dwLastError = ERROR_NO_MAPFILE;
SetLastError(ERROR_NO_MAPFILE);
return FALSE;
}
if(NETRGUSER_CFM_CODE != pHeader->dwConfirmCode)
{
m_dwLastError = ERROR_INVALID_CFMCODE;
SetLastError(ERROR_INVALID_CFMCODE);
return FALSE;
}
if(NETRGUSER_CMD_NONE == pHeader->nCommandCode)
{
m_dwLastError = ERROR_INVALID_CMDCODE;
SetLastError(ERROR_INVALID_CMDCODE);
return FALSE;
}
if(pHeader->dwDataSize > dwBufSize)
{
m_dwLastError = ERROR_BUFFER_OVERFLOW;
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
if(pHeader->nCommandCode != dwCommandCode)
{
m_dwLastError = ERROR_INVALID_CMDCODE;
SetLastError(ERROR_INVALID_CMDCODE);
return FALSE;
}
ZeroMemory(pOutBuf, dwBufSize);
// 拷贝数据到缓冲区
memcpy(pOutBuf, pHeader->bInfo, pHeader->dwDataSize);
int ret = pHeader->dwDataSize;
pHeader->dwReserved[2] = 0;
return ret;
}
BOOL CFFMClient::WriteCmdData(DWORD memSize, DWORD nCommandCode, DWORD dwDataSize, const LPVOID pBuf)
{
if(!memSize)
{
memSize = DEFAULT_MAPSIZE;
}
m_dwSize = memSize;
// 检验数据的合理性
if(NULL == GetBuffer())
{
m_dwLastError = ERROR_NO_MAPFILE;
SetLastError(ERROR_NO_MAPFILE);
return FALSE;
}
if(NETRGUSER_CMD_NONE == nCommandCode)
{
m_dwLastError = ERROR_INVALID_CMDCODE;
SetLastError(ERROR_INVALID_CMDCODE);
return FALSE;
}
if(dwDataSize > 0 && pBuf == NULL)
{
m_dwLastError = ERROR_INVALID_USER_BUFFER;
SetLastError(ERROR_INVALID_USER_BUFFER);
return FALSE;
}
if(dwDataSize + sizeof(DATA_HEADER) > GetSize())
{
m_dwLastError = ERROR_BUFFER_OVERFLOW;
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
// 填写数据结构
// 文件头
DATA_HEADER dataHeader;
dataHeader.nCommandCode = nCommandCode;
dataHeader.dwDataSize = dwDataSize;
ZeroMemory(GetBuffer(), GetSize());
memcpy(GetBuffer(), &dataHeader, sizeof(DATA_HEADER));
// 数据块
LPDATA_HEADER pData = (LPDATA_HEADER)GetBuffer();
memcpy(pData->bInfo, pBuf, dwDataSize);
return TRUE;
}
BOOL CFFMClient::CanRead()
{
LPDATA_HEADER pData = (LPDATA_HEADER)GetBuffer();
bool ret = pData->dwReserved[CLINET_FLAG] == 1;
return ret;
}
BOOL CFFMClient::IsOver()
{
LPDATA_HEADER pData = (LPDATA_HEADER)GetBuffer();
return pData->dwReserved[5] == 10;
}
// 获取内存文件大小
DWORD CFFMClient::GetSize()
{
return m_dwSize;
}
代码测试
服务端测试代码
// ServerCom.cpp : Defines the entry point for the console application.
//
// Max size of the file mapping object.
// File offset where the view is to begin.
// The number of bytes of a file mapping to map to the view. All bytes of the
// view must be within the maximum size of the file mapping object (MAP_SIZE).
// If VIEW_SIZE is 0, the mapping extends from the offset (VIEW_OFFSET) to
// the end of the file mapping.
// Unicode string message to be written to the mapped view. Its size in byte
// must be less than the view size (VIEW_SIZE).
int main_0(int argc, char* argv[])
{
HANDLE hMapFile = NULL;
PVOID pView = NULL;
// Create the file mapping object.
hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE, // Use paging file - shared memory
NULL, // Default security attributes
PAGE_READWRITE, // Allow read and write access
0, // High-order DWORD of file mapping max size
MAP_SIZE, // Low-order DWORD of file mapping max size
FULL_MAP_NAME // Name of the file mapping object
);
if (hMapFile == NULL)
{
wprintf(L"CreateFileMapping failed w/err 0x%08lx\n", GetLastError());
goto Cleanup;
}
wprintf(L"The file mapping (%s) is created\n", FULL_MAP_NAME);
// Map a view of the file mapping into the address space of the current
// process.
pView = MapViewOfFile(
hMapFile, // Handle of the map object
FILE_MAP_ALL_ACCESS, // Read and write access
0, // High-order DWORD of the file offset
VIEW_OFFSET, // Low-order DWORD of the file offset
VIEW_SIZE // The number of bytes to map to view
);
if (pView == NULL)
{
wprintf(L"MapViewOfFile failed w/err 0x%08lx\n", GetLastError());
goto Cleanup;
}
wprintf(L"The file view is mapped\n");
// Prepare a message to be written to the view.
PWSTR pszMessage = MESSAGE;
DWORD cbMessage = (wcslen(pszMessage) + 1) * sizeof(*pszMessage);
// Write the message to the view.
memcpy_s(pView, VIEW_SIZE, pszMessage, cbMessage);
wprintf(L"This message is written to the view:\n\"%s\"\n",
pszMessage);
// Wait to clean up resources and stop the process.
wprintf(L"Press ENTER to clean up resources and quit");
getchar();
Cleanup:
if (hMapFile)
{
if (pView)
{
// Unmap the file view.
UnmapViewOfFile(pView);
pView = NULL;
}
// Close the file mapping object.
CloseHandle(hMapFile);
hMapFile = NULL;
}
return 0;
}
//开始时间
LARGE_INTEGER beginTickCount()
{
LARGE_INTEGER frequency, startCount, stopCount;
bool ret;
//返回性能计数器每秒滴答的个数
ret = QueryPerformanceFrequency(&frequency);
if (ret) {
ret = QueryPerformanceCounter(&startCount);
}
return startCount;
}
//计算经过时间时间
LONGLONG calcPassTimeMicrosecond(LARGE_INTEGER &startCount, LARGE_INTEGER &stopCount)
{
bool ret;
LARGE_INTEGER frequency;
LONGLONG elapsed;
//返回性能计数器每秒滴答的个数
ret = QueryPerformanceFrequency(&frequency);
if (ret) {
elapsed = (stopCount.QuadPart - startCount.QuadPart) * 1000000 / frequency.QuadPart;
cout << "QueryPerformanceFrequency & QueryPerformanceCounter =" << elapsed << "us" << endl;
}
return elapsed;
}
/**
* QueryPerformanceCounter的精度为us级
*/
const unsigned long SLEEP_TIME_MILL = 10;
void calcByQueryPerformanceCounter() {
LARGE_INTEGER frequency, startCount, stopCount;
bool ret;
//返回性能计数器每秒滴答的个数
ret = QueryPerformanceFrequency(&frequency);
if (ret) {
ret = QueryPerformanceCounter(&startCount);
}
Sleep(SLEEP_TIME_MILL);
if (ret) {
QueryPerformanceCounter(&stopCount);
}
if (ret) {
LONGLONG elapsed = (stopCount.QuadPart - startCount.QuadPart) * 1000000 / frequency.QuadPart;
//cout << "QueryPerformanceFrequency & QueryPerformanceCounter =" << elapsed << "us";
}
}
void running(int seconds)
{
Sleep(seconds * 1000);
cout << "Sleep for " << seconds << "秒" << endl;
}
int main()
{
//double df = 1e17;
CFFMServer* cff = new CFFMServer();
cff->Create();
char *aa = new char[200 << 20];
char *bb = new char[200 << 20];
for (int i = 0; i < (200 << 20); i++)
{
aa[i] = i;
}
int count = 1024;
clock_t benin, end;
unsigned int mm = 0;
OutputDebugString("调试信息:\n");
printf("开始写入共享内存数据.......\n");
benin = clock();
char szTime[64];
double dTime = (double)benin;
ZeroMemory(szTime, 64);
sprintf(szTime, "%f", dTime);
DWORD startTime = GetTickCount();//计时开始
LARGE_INTEGER _frequency, _startCount, _stopCount;
LONGLONG _elapsed;
_startCount = beginTickCount();
//auto tp1 = std::chrono::high_resolution_clock::now().time_since_epoch().count();
//cout << "获取系统时间戳::std::chrono::high_resolution_clock::now():" << tp1 << "纳秒" << endl;
//auto tp2 = std::chrono::system_clock::now().time_since_epoch().count();
//cout << "获取系统时间戳:std::chrono::system_clock::now().time_since_epoch().count=" << tp2 << "100纳秒" << endl;
//auto tp3 = std::chrono::steady_clock::now().time_since_epoch().count();
//cout << "获取系统时间戳:std::chrono::steady_clock::now().time_since_epoch().count=" << tp3 << "纳秒" << endl;
//auto tp4 = std::chrono::system_clock::now();
//std::time_t tt = std::chrono::system_clock::to_time_t(tp4); //微秒
//std::cout << "seconds from 1970-01-01 00:00:00 UTC:" << tt << std::endl; //应该不是从1970年以来的微秒数,而是从开机以来经过的微秒数
时间间隔
//auto tp5 = std::chrono::steady_clock::now();
//Sleep(100);
//auto tp6 = std::chrono::steady_clock::now();
//cout << "间隔时间微秒:" << std::chrono::duration_cast<std::chrono::microseconds>(tp6 - tp5).count() << "微秒" << endl;
//cout << "间隔时间纳秒:" << std::chrono::duration_cast<std::chrono::nanoseconds>(tp6 - tp5).count() << "纳秒" << endl;
//std::chrono::system_clock::time_point tt1; //默认值为 1970-01-01 08:00:00 即0
//std::chrono::system_clock::time_point tt2(std::chrono::seconds(2));
//cout << "初始化:std::chrono::system_clock::time_point start_time2(std::chrono::seconds(2))="
// << tt2.time_since_epoch().count() << "默认单位是微秒" << endl;
//cout << "std::chrono::duration_cast<std::chrono::nanoseconds>(tt2.time_since_epoch()).count()="
// << std::chrono::duration_cast<std::chrono::nanoseconds>(tt2.time_since_epoch()).count() << "纳秒" << endl;
//cout << "std::chrono::duration_cast<std::chrono::microseconds>(tt2.time_since_epoch()).count()= "
// << std::chrono::duration_cast<std::chrono::microseconds>(tt2.time_since_epoch()).count() << "微秒" << endl;
//cout << "std::chrono::duration_cast<std::chrono::milliseconds>(tt2.time_since_epoch()).count() = "
// << std::chrono::duration_cast<std::chrono::milliseconds>(tt2.time_since_epoch()).count() << "毫秒" << endl;
//cout << "std::chrono::duration_cast<std::chrono::seconds>(tt2.time_since_epoch()).count()="
// << std::chrono::duration_cast<std::chrono::seconds>(tt2.time_since_epoch()).count() << "秒" << endl;
//cout << "当前时间戳:std::chrono::system_clock::now().time_since_epoch().count()精度是100纳秒" << std::chrono::system_clock::now().time_since_epoch().count() << endl;
测试时钟精度
//cout << "system clock : ";
//cout << chrono::system_clock::period::num << "/" << chrono::system_clock::period::den << "s" << endl;
//cout << "steady clock : ";
//cout << chrono::steady_clock::period::num << "/" << chrono::steady_clock::period::den << "s" << endl;
//cout << "high resolution clock : ";
//cout << chrono::high_resolution_clock::period::num << "/" << chrono::high_resolution_clock::period::den << "s" << endl;
//
//_XTIME_NSECS_PER_TICK 100纳秒
//steady_clock high_resolution_clock
//SYSTEM_INFO systemInfo;
//GetSystemInfo(&systemInfo);
//int cpuNumber = systemInfo.dwNumberOfProcessors;
//SetThreadAffinityMask(GetCurrentThread(), 0x00000001); //线程运行在1号cpu
LARGE_INTEGER startTimeCalc, endTimeCalc;
LARGE_INTEGER freqCalc;
QueryPerformanceFrequency(&freqCalc);
QueryPerformanceCounter(&startTimeCalc);
//cout << "start.QuarPart = " << startTimeCalc.QuadPart << endl;
//running(1); //暂停1秒
//QueryPerformanceCounter(&endTimeCalc);
//cout << "end.QuarPart = " << endTimeCalc.QuadPart << endl;
//std::cout << "consume value = end.QuadPart - start.QuadPart = " << (endTimeCalc.QuadPart - startTimeCalc.QuadPart) << std::endl;
//std::cout << "(consume value/(double)freq.QuadPart) Time consumed = " << (endTimeCalc.QuadPart - startTimeCalc.QuadPart) / (double)freqCalc.QuadPart << "(s)" << std::endl; //output consumed time
while (count > 0)
{
if (cff->CanWrite())
{
if (count == 1024 - 1)
{
benin = clock();
}
aa[0] = mm;
mm++;
cff->WriteCmdData(2, 200 << 20, aa);
count--;
}
else
{
// Sleep(1);
}
}
cff->WriteOver();
_stopCount = beginTickCount();
_elapsed = calcPassTimeMicrosecond(_startCount, _stopCount);
cout << "服务端写入2G数据用时:" << _elapsed << "微秒" << endl;
cout << "*******************" << endl;
end = clock();
printf("服务端写入2G数据用时:%f\n", (end - benin) / 1000.0);
/*CRITICAL_SECTION cs;
EnterCriticalSection(&cs);*/
_startCount = beginTickCount();
memcpy(bb, aa, (2 << 20));
_stopCount = beginTickCount();
_elapsed = calcPassTimeMicrosecond(_startCount, _stopCount);
cout << "服务端memcpy写入200兆数据用时:" << _elapsed << "微秒" << endl;
//LeaveCriticalSection(&cs);
DWORD endTime = GetTickCount();//计时结束
//printf("服务端写入2G数据用时:%f\n", (end - begin) / CLOCKS_PER_SEC);
//printf("服务端写入2G数据用时:%f\n", (endTime - startTime));
//cout << "服务端写入2G数据用时:" << endTime - startTime << "毫秒" << endl;
fflush(stdout);
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<LONGLONG>(1000)));
system("pause");
return 0;
}
客户端测试代码
// ClientCom.cpp : Defines the entry point for the console application.
//
// File offset where the view is to begin.
// The number of bytes of a file mapping to map to the view. All bytes of the
// view must be within the maximum size of the file mapping object. If
// VIEW_SIZE is 0, the mapping extends from the offset (VIEW_OFFSET) to the
// end of the file mapping.
int main_1(int argc, char* argv[])
{
HANDLE hMapFile = NULL;
PVOID pView = NULL;
// Try to open the named file mapping identified by the map name.
hMapFile = OpenFileMapping(
FILE_MAP_READ, // Read access
FALSE, // Do not inherit the name
FULL_MAP_NAME // File mapping name
);
if(hMapFile == NULL)
{
wprintf(L"OpenFileMapping failed w/err 0x%08lx\n", GetLastError());
goto Cleanup;
}
wprintf(L"The file mapping (%s) is opened\n", FULL_MAP_NAME);
// Map a view of the file mapping into the address space of the current
// process.
pView = MapViewOfFile(
hMapFile, // Handle of the map object
FILE_MAP_READ, // Read access
0, // High-order DWORD of the file offset
VIEW_OFFSET, // Low-order DWORD of the file offset
VIEW_SIZE // The number of bytes to map to view
);
if(pView == NULL)
{
wprintf(L"MapViewOfFile failed w/err 0x%08lx\n", GetLastError());
goto Cleanup;
}
wprintf(L"The file view is mapped\n");
// Read and display the content in view.
wprintf(L"Read from the file mapping:\n\"%s\"\n", (PWSTR)pView);
// Wait to clean up resources and stop the process.
wprintf(L"Press ENTER to clean up resources and quit");
getchar();
Cleanup:
if(hMapFile)
{
if(pView)
{
// Unmap the file view.
UnmapViewOfFile(pView);
pView = NULL;
}
// Close the file mapping object.
CloseHandle(hMapFile);
hMapFile = NULL;
}
return 0;
}
int main(int argc, char* argv[])
{
CFFMClient* ff = new CFFMClient();
ff->Open();
int cmd = 2;
FILE* fp = fopen("./test_222.dat", "wb");
char* buf = new char[201 << 20];
long long int cccc = 0;
int countxx = 0;
clock_t begin, end;
printf("客户端读取数据...\n");
begin = clock();
while(true)
{
if(ff->CanRead())
{
int ret = ff->ReadCmdData(cmd, 201 << 20, buf);
int tt = fwrite(buf, 1, ret, fp);
cccc+=tt;
countxx++;
}
else
{
// Sleep(1);
}
if(ff->IsOver())
{
end = clock();
printf("%f\n", (end - begin) / 1000.0);
break;
}
}
printf("服务端写入200兆数据用时:%f\n", (end - begin) / 1000.0);
fflush(stdout);
fclose(fp);
system("pause");
return 0;
}