critical section问题在windows中可以用CRITICAL_SECTION,mutex之类的解决
mutex可跨进程,但每次PV都要进入内核模式
CRITICAL_SECTION减少了系统调用的次数,但不能跨进程
这里尝试做一个能跨进程并且减少系统调用的次数的同步类
CSLock.h
#ifndef CSLOCK_H_INCLUDED #define CSLOCK_H_INCLUDED class CSLock { public: enum Disposition{OpenExisting,OpenAlways,CreateNew}; private: typedef struct _LOCK_SHARED_DATA { LONG Key; DWORD OwnerId; DWORD SpinCount; LONG WaitingCount; TCHAR EventName[12]; }LOCK_SHARED_DATA,*PLOCK_SHARED_DATA; DWORD EntryCount; HANDLE hSection,hEvent; PLOCK_SHARED_DATA SharedData; bool Opened; bool Create(const TCHAR*Name,CSLock::Disposition CreateDisposition,DWORD SpinCount); bool Close(); public: bool Acquire(DWORD Timeout=INFINITE,bool Alertable=false); bool Release(); bool IsOpened()const; bool Recreate(const TCHAR*Name,CSLock::Disposition CreateDisposition,DWORD SpinCount=128); CSLock(const TCHAR*Name,CSLock::Disposition CreateDisposition=CSLock::OpenAlways,DWORD SpinCount=128); ~CSLock(); }; #endif // CSLOCK_H_INCLUDED
#include<windows.h> #include<tchar.h> #include"CSLock.h" //#include<stdio.h> const TCHAR DefEventName[]=TEXT("ovaltransferrin"); bool CSLock::Create(const TCHAR*Name,CSLock::Disposition CreateDisposition,DWORD SpinCount) { DWORD NameLength,MappingSize; NameLength=Name?_tcslen(Name):sizeof(DefEventName)-sizeof(TCHAR); MappingSize=sizeof(LOCK_SHARED_DATA)+NameLength*sizeof(TCHAR); if(CreateDisposition==CSLock::OpenExisting) this->hSection=OpenFileMapping(FILE_MAP_WRITE,FALSE,Name); else this->hSection=CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE|SEC_COMMIT,0,MappingSize,Name); if(this->hSection) { bool AlreadyExists=(GetLastError()==ERROR_ALREADY_EXISTS)||(CreateDisposition==CSLock::OpenExisting); if(CreateDisposition==CSLock::CreateNew&&AlreadyExists) { CloseHandle(this->hSection); return false; } this->SharedData=static_cast<CSLock::PLOCK_SHARED_DATA>(MapViewOfFileEx(this->hSection,FILE_MAP_WRITE,0,0,0,NULL)); if(this->SharedData) { if(!AlreadyExists) { SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); this->SharedData->Key=1; this->SharedData->OwnerId=0; this->SharedData->SpinCount=sysinfo.dwNumberOfProcessors>1?SpinCount:0; this->SharedData->WaitingCount=0; _tcscpy(this->SharedData->EventName,Name?Name:DefEventName); for(int tryc=0;tryc<255;++tryc) { FILETIME systime; GetSystemTimeAsFileTime(&systime); _ultot(systime.dwLowDateTime+systime.dwHighDateTime,this->SharedData->EventName+NameLength,16); this->hEvent=CreateEvent(NULL,TRUE,FALSE,this->SharedData->EventName); if(this->hEvent&&GetLastError()==ERROR_ALREADY_EXISTS) { CloseHandle(this->hEvent); }else if(GetLastError()!=ERROR_ACCESS_DENIED)return true; } }else { this->hEvent=OpenEvent(SYNCHRONIZE,FALSE,this->SharedData->EventName); if(this->hEvent)return true; } UnmapViewOfFile(this->SharedData); } } return false; } bool CSLock::Acquire(DWORD Timeout,bool Alertable) { if(this->SharedData->OwnerId!=GetCurrentThreadId()) { DWORD i(this->SharedData->SpinCount); InterlockedIncrement(&this->SharedData->WaitingCount); while(InterlockedExchange(&this->SharedData->Key,0)==0&&i--); if(i==DWORD(-1)) { if(Timeout==0) { InterlockedDecrement(&this->SharedData->WaitingCount); return false; } do { DWORD r=WaitForSingleObjectEx(this->hEvent,Timeout,Alertable); if(r==WAIT_OBJECT_0) { if(InterlockedExchange(&this->SharedData->Key,0)) { ResetEvent(this->hEvent); break; } }else { InterlockedDecrement(&this->SharedData->WaitingCount); return false; } }while(1); } InterlockedDecrement(&this->SharedData->WaitingCount); this->SharedData->OwnerId=GetCurrentThreadId(); } ++this->EntryCount; return true; } bool CSLock::Release() { if(this->SharedData->OwnerId==GetCurrentThreadId()) { if(--this->EntryCount==0) { this->SharedData->OwnerId=0; InterlockedExchange(&this->SharedData->Key,1); if(InterlockedCompareExchange(&this->SharedData->WaitingCount,0,0))SetEvent(this->hEvent); } return true; } return false; } bool CSLock::IsOpened()const { return this->Opened; } bool CSLock::Close() { if(this->Opened) { CloseHandle(this->hEvent); UnmapViewOfFile(this->SharedData); CloseHandle(this->hSection); this->Opened=false; return true; }else return false; } bool CSLock::Recreate(const TCHAR*Name,CSLock::Disposition CreateDisposition,DWORD SpinCount) { CSLock::Close(); return CSLock::Create(Name,CreateDisposition,SpinCount); } CSLock::CSLock(const TCHAR*Name,CSLock::Disposition CreateDisposition,DWORD SpinCount):EntryCount(0),Opened(CSLock::Create(Name,CreateDisposition,SpinCount)) { } CSLock::~CSLock() { CSLock::Close(); }
#include <iostream> #include <windows.h> #include <conio.h> #include "CSLock.h" using namespace std; int main() { CSLock c("x"); cout<<"opened:"<<c.IsOpened()<<endl; c.Acquire(); cout << "pid:"<<GetCurrentProcessId() << endl; getch(); c.Release(); cout<<"quit"<<endl; getch(); return 0; }