From c9ae7e236fb4c4ca88dadb7844a2f4a629c7d1b4 Mon Sep 17 00:00:00 2001 From: sauron Date: Thu, 4 Sep 2025 14:13:05 +0900 Subject: [PATCH] commit 2025-09-04 14:13 add ZCppMain/ZCProcess.H & ZCppMainTest/ZtCThreadEx_000.cpp --- ZCppMain/ZCProcess.H | 1556 +++++++++++++ ZCppMain/ZCProcess_Linux.H | 4678 ++++++++++++++++++++++++++++++++++++++ ZCppMain/ZCProcess_Win.H | 3151 +++++++++++++++++++++++++ ZCppMain/ZCStringStd.H | 4 +- ZCppMain/ZMainHead.H | 18 +- ZCppMain/ZMainHeadEx.H | 5 +- ZCppMain/ZtCSimList.H | 18 +- ZCppMainTest/ZtCThreadEx_000.cpp | 170 ++ 8 files changed, 9579 insertions(+), 21 deletions(-) create mode 100644 ZCppMain/ZCProcess.H create mode 100644 ZCppMain/ZCProcess_Linux.H create mode 100644 ZCppMain/ZCProcess_Win.H create mode 100644 ZCppMainTest/ZtCThreadEx_000.cpp diff --git a/ZCppMain/ZCProcess.H b/ZCppMain/ZCProcess.H new file mode 100644 index 0000000..6834a4b --- /dev/null +++ b/ZCppMain/ZCProcess.H @@ -0,0 +1,1556 @@ + + +#ifndef __ZCPPMAIN__PROCESS_H__ +#define __ZCPPMAIN__PROCESS_H__ + + +#include +#include "ZCppMain/ZMainHead.H" + +#ifdef _DEBUG_CEXCEPT_EXIT_ + #include +#endif + +namespace ZNsMain +{ + + namespace ZNsIFace + { + + class ZISyncEasy + { + public: + bool Lock (){return false;} + bool UnLock(){return false;} + public: + };/* + class ZISyncEasy*/ + + }/* + namespace ZNsIFace*/ + + + template class ZtCExceptSync : public ZNsMain::ZCExceptBase + { + private: + int mi_ErrNum ; + int mi_LineNum ; + TString mo_FileName; + public : + + ZtCExceptSync(int AI_LineNum=0): mi_LineNum(AI_LineNum){mi_ErrNum=0;} + + ZtCExceptSync(const char* AP_FileName, int AI_LineNum=0, int AI_ErrNum=0): mi_LineNum(AI_LineNum) + { + mi_ErrNum =AI_ErrNum ; + mo_FileName=AP_FileName; + + #ifdef _DEBUG_CEXCEPT_EXIT_ + std::cerr<<"★★ FileName="< + class ZtCSyncCount : public TSemaphore /////////////////// + { + protected: + int mi_LockCount; + public : + + ZtCSyncCount(int AI_LockCount=0) : TSemaphore() + { + mi_LockCount=AI_LockCount; + }/* + ZtCSyncCount(int AI_LockCount=0)*/ + + bool LockCount() + { + --mi_LockCount; return this->TSemaphore::Lock(); + }/* + bool LockCount()*/ + + template + bool LockCount(TSyncExec& AR_CSyncExec) + { + --mi_LockCount; + + AR_CSyncExec.UnLock(); + { + if(this->TSemaphore::Lock()==false) return false; + } + AR_CSyncExec.Lock(); + + return false; + }/* + template + bool LockCount(TSyncExec& AR_CSyncExec) */ + + + // cf) linux 의 semctl(), semop() 계열의 세마포어에서는 LockTime() 함수가 없다. + + template + int LockCountTime(TSyncExec& AR_CSyncExec, int AI_TimeOutMili) + { + int VI_LockCode=ZNsMain::ZNsEnum::ZEThread_OK; + + --mi_LockCount; + + AR_CSyncExec.UnLock(); + { + VI_LockCode=this->TSemaphore::LockTime(AI_TimeOutMili); + } + AR_CSyncExec.Lock(); + + if(VI_LockCode==ZNsMain::ZNsEnum::ZEThread_TimeOut) + { + ++mi_LockCount; + }/* + if(VI_LockCode==ZNsMain::ZNsEnum::ZEThread_TimeOut)*/ + + return VI_LockCode; + }/* + template + int LockCountTime(TSyncExec& AR_CSyncExec, int AI_TimeOutMili) */ + + bool UnLockCount() + { + ++mi_LockCount; return this->TSemaphore::UnLock(); + }/* + bool UnLockCount()*/ + + int GetLockCount() const + { + return mi_LockCount; + }/* + int GetLockCount() const*/ + + public: + };/* + template< typename TSemaphore=ZNsMain::ZCThreadSemaphore + > + class ZtCSyncCount : public TSemaphore /////////////////*/ + + + /*//////////////////////////////////////////////////////////// + + ■ class ZtCSyncCountRef 는 ZtCSyncCount 와 비슷하지만, 대기 + 동기화 object 를 생성자에서 참조로 받는다는 것이 다르다. + + ////////////////////////////////////////////////////////////*/ + + template< typename TSemaphore=ZNsMain::ZCThreadSemaphore + > + class ZtCSyncCountRef //////////////////////////////////// + { + private : + + ZtCSyncCountRef(const ZtCSyncCountRef& rhs) + { + }/* + ZtCSyncCountRef(const ZtCSyncCountRef& rhs)*/ + + ZtCSyncCountRef& operator=(const ZtCSyncCountRef& rhs) + { + return *this; + }/* + ZtCSyncCountRef& operator=(const ZtCSyncCountRef& rhs)*/ + + protected: + TSemaphore& mr_CSemaphore; + int mi_LockCount ; + public : + + ZtCSyncCountRef(TSemaphore& AR_CSemaphore, int AI_LockCount) : + mr_CSemaphore(AR_CSemaphore) + { + mi_LockCount=AI_LockCount; + }/* + ZtCSyncCountRef(TSemaphore& AR_CSemaphore, int AI_LockCount)*/ + + bool LockCount() + { + --mi_LockCount; return mr_CSemaphore.Lock(); + }/* + bool LockCount()*/ + + template + bool LockCount(TSyncExec& AR_CSyncExec) + { + --mi_LockCount; + + AR_CSyncExec.UnLock(); + { + if(mr_CSemaphore.Lock()==false) return false; + } + AR_CSyncExec.Lock(); + + return true; + }/* + template + bool LockCount(TSyncExec& AR_CSyncExec) */ + + template + int LockCountTime(TSyncExec& AR_CSyncExec, int AI_TimeOutMili) + { + int VI_LockCode=ZNsMain::ZNsEnum::ZEThread_OK; + + --mi_LockCount; + + AR_CSyncExec.UnLock(); + { + VI_LockCode=mr_CSemaphore.LockTime(AI_TimeOutMili); + } + AR_CSyncExec.Lock(); + + if(VI_LockCode==ZNsMain::ZNsEnum::ZEThread_TimeOut) + { + ++mi_LockCount; + }/* + if(VI_LockCode==ZNsMain::ZNsEnum::ZEThread_TimeOut)*/ + + return VI_LockCode; + }/* + template + int LockCountTime(TSyncExec& AR_CSyncExec, int AI_TimeOutMili) */ + + bool UnLockCount() + { + ++mi_LockCount; return mr_CSemaphore.UnLock(); + }/* + bool UnLockCount()*/ + + int GetLockCount() const + { + return mi_LockCount; + }/* + int GetLockCount() const*/ + + public: + };/* + template< typename TSemaphore=ZNsMain::ZCThreadSemaphore + > + class ZtCSyncCountRef //////////////////////////////////*/ + + + /*/////////////////////////////////////////////////////////////////////////////////// + + ■ ZtCThreadEx<> 클래스 템플릿은 ZNsMain::ZtCThread<> 와는 달리 반드시 상속해서 사용해야 + 하며, 상속함수에서 Exec() 함수를 재정의하면 된다. + + 필요하면 Init(), Fini() 도 재정의한다. + + ■ void Exec(THelpKey AR_HelpKey) 멤버를 사용하고 싶다면 + + Init(AR_HelpKey), Fini(AR_HelpKey), Exec(AR_HelpKey) + + 함수는 상속 클래스에서 public 함수로 선언하는 것이 좋겠다. 이게 싫다면 상속클래스 + ZtCThreadEx<>::ZtCHelpKeyParam<> 템플릿에 대하여 friend 선언을 해주어야 하는데 약 + 간 귀찮은 일이다. + + cf) template template friend class A::B; + + ■ 2 개의 템플릿 인자를 갖는 멤버 Exec2(THelpKey1, THelpKey2) 를 Exec 멤버를 중첩시켜 + Exec(THelpKey1,THelpKey2) 처럼 하면 멤버 은폐로 인해 골치아픈 일이 발생하게 된다. + + ZtCThreadEx<> 클래스 템플릿은 반드시 상속해서 사용하고 있는데, 상속 클래스에서 Exec(THelpKey1) + 을 재정의하면, 멤버 '은폐'로 인해 기존에 상속클래스에서 + + Init(THelpKey1), Fini(THelpKey1) + + 를 재정의하지 않은 경우에, 모두 재정의해야한다. 상속 클래스에서 재정의하지 않으면 + 기본적으로 + + ZtCThreadEx<>::Init(THelpKey1) + ZtCThreadEx<>::Fini(THelpKey1) + + 이것이 호출되리라는 편견(?)은 버려야 한다. + + -- 2010-02-21 20:05:00 + + Exec2(THelpKey1,THelpKey2) 을 사용하는 경우, 상속 클래스에서 + Init2(THelpKey1,THelpKey2) 와 + Fini2(THelpKey1,THelpKey2) 를 같이 정의해주어야 한다. + + CWorkPool.H 의 + + CTypeCtrlSnglAllocWork_T<>::CSnglAllocWork::Init2(~) + CTypeCtrlSnglAllocWork_T<>::CSnglAllocWork::Fini2(~) + + 정의에서 + + this->CThreadBase::template Init (AR_HelpKey1, AR_HelpKey2) + this->CThreadBase::template Fini (AR_HelpKey1, AR_HelpKey2) + + 가 아니라, + + this->CThreadBase::template Init2(AR_HelpKey1, AR_HelpKey2) + this->CThreadBase::template Fini2(AR_HelpKey1, AR_HelpKey2) + + 이 맞다. 이것 때문에 2~3 시간 헤맸다. + + -- 2011-02-03 14:34:00 + + ///////////////////////////////////////////////////////////////////////////////////*/ + + template< typename TDerive, typename TThread=ZtCThread<> + > + class ZtCThreadEx : public TThread /////////////////////// + { + public : + typedef ZtCThreadEx ZCThreadEx; + typedef TDerive ZCDerive ; + protected: + + + template class ZtCHelpKeyParam + { + private: + friend class ZtCThreadEx; + private: + THelpKey mr_HelpKey; + ZCDerive* mp_CDerive; + private: + + ZtCHelpKeyParam(THelpKey AR_HelpKey, ZCDerive& AR_CDerive) : + mr_HelpKey(AR_HelpKey) + { + mp_CDerive = &AR_CDerive; + }/* + ZtCHelpKeyParam(THelpKey AR_HelpKey, ZCDerive& AR_CDerive)*/ + + /*//////////////////////////////////////////////////////////////////////// + + ■ (*mp_CDerive) 의 멤버 Init,Exec,Fini 는 반드시 템플릿 멤버이어야 한다. + "->template" 형식의 템플릿 멤버 표기로 접근하고 있기 때문이다. + + -- 2009-08-01 20:05:00 + + ////////////////////////////////////////////////////////////////////////*/ + + + #if(_CODE_OLD_) + void Init(){mp_CDerive->template Init(mr_HelpKey);} + void Exec(){mp_CDerive->template Exec(mr_HelpKey);} + void Fini(){mp_CDerive->template Fini(mr_HelpKey);} + #else + void Init(){mp_CDerive->Init(mr_HelpKey);} + void Exec(){mp_CDerive->Exec(mr_HelpKey);} + void Fini(){mp_CDerive->Fini(mr_HelpKey);} + #endif + + private: + };/* + template class ZtCHelpKeyParam */ + + + template class ZtCHelpKeyParam2 + { + private: + friend class ZtCThreadEx; + private: + THelpKey1 mr_HelpKey1; + THelpKey2 mr_HelpKey2; + ZCDerive* mp_CDerive ; + private: + + ZtCHelpKeyParam2(THelpKey1 AR_HelpKey1, THelpKey2 AR_HelpKey2, ZCDerive& AR_CDerive) : + mr_HelpKey1(AR_HelpKey1), mr_HelpKey2(AR_HelpKey2) + { + mp_CDerive=&AR_CDerive; + }/* + ZtCHelpKeyParam2(THelpKey1 AR_HelpKey1, THelpKey2 AR_HelpKey2, ZCDerive& AR_CDerive)*/ + + /*//////////////////////////////////////////////////////////////////////// + + ■ (*mp_CDerive) 의 멤버 Init, Exec, Fini 는 반드시 템플릿 멤버이어야 한다. + "->template" 형식의 템플릿 멤버 표기로 접근하고 있기 때문이다. + + -- 2009-08-01 20:05:00 + + ////////////////////////////////////////////////////////////////////////*/ + + #if(_CODE_OLD_) + void Init2(){mp_CDerive->template Init2(mr_HelpKey1, mr_HelpKey2);} + void Exec2(){mp_CDerive->template Exec2(mr_HelpKey1, mr_HelpKey2);} + void Fini2(){mp_CDerive->template Fini2(mr_HelpKey1, mr_HelpKey2);} + #else + void Init(){mp_CDerive->Init(mr_HelpKey1, mr_HelpKey2);} + void Exec(){mp_CDerive->Exec(mr_HelpKey1, mr_HelpKey2);} + void Fini(){mp_CDerive->Fini(mr_HelpKey1, mr_HelpKey2);} + #endif + + private: + };/* + template class ZtCHelpKeyParam2 */ + + + template< typename THelpKey1, typename THelpKey2, typename THelpKey3 + > + class ZtCHelpKeyParam3 /////////////////////////////////////////////// + { + private: + friend class ZtCThreadEx; + private: + THelpKey1 mr_HelpKey1; + THelpKey2 mr_HelpKey2; + THelpKey3 mr_HelpKey3; + ZCDerive* mp_CDerive ; + private: + + ZtCHelpKeyParam3 /*:::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + ( + THelpKey1 AR_HelpKey1, THelpKey2 AR_HelpKey2, + THelpKey3 AR_HelpKey3, ZCDerive& AR_CDerive + ) : + mr_HelpKey1(AR_HelpKey1), mr_HelpKey2(AR_HelpKey2), mr_HelpKey3(AR_HelpKey3) + { + mp_CDerive=&AR_CDerive; + }/* + ZtCHelpKeyParam3(THelpKey1 AR_HelpKey1, THelpKey2 AR_HelpKey2, THelpKey3 AR_HelpKey3, ZCDerive& AR_CDerive)*/ + + /*//////////////////////////////////////////////////////////////////////// + + ■ (*mp_CDerive) 의 멤버 Init, Exec, Fini 는 반드시 템플릿 멤버이어야 한다. + "->template" 형식의 템플릿 멤버 표기로 접근하고 있기 때문이다. + + -- 2009-08-01 20:05:00 + + ////////////////////////////////////////////////////////////////////////*/ + + #if(_CODE_OLD_) + void Init3(){mp_CDerive->template Init3(mr_HelpKey1, mr_HelpKey2, mr_HelpKey3);} + void Exec3(){mp_CDerive->template Exec3(mr_HelpKey1, mr_HelpKey2, mr_HelpKey3);} + void Fini3(){mp_CDerive->template Fini3(mr_HelpKey1, mr_HelpKey2, mr_HelpKey3);} + #else + void Init(){mp_CDerive->Init(mr_HelpKey1, mr_HelpKey2, mr_HelpKey3);} + void Exec(){mp_CDerive->Exec(mr_HelpKey1, mr_HelpKey2, mr_HelpKey3);} + void Fini(){mp_CDerive->Fini(mr_HelpKey1, mr_HelpKey2, mr_HelpKey3);} + #endif + public: + };/* + template< typename THelpKey1, typename THelpKey2, typename THelpKey3 + > + class ZtCHelpKeyParam3 /////////////////////////////////////////////*/ + + + /*protected:*/ + protected: + + _VT_ void Init() + { + this->TThread::Detach(); // linux 에서는 아주 중요한 코드이다. + + #ifdef _DEBUG + std::cout<<"ZCThreadEx::Init()"< _VT_ void Init(THelpKey) + { + this->TThread::Detach(); // linux 에서는 아주 중요한 코드이다. + + #ifdef _DEBUG + std::cout<<"▶ ZCThreadEx::Init(THelpKey), THelpKey typename="< _VT_ void Init(THelpKey)*/ + + template _VT_ void Init(THelpKey1, THelpKey2) + { + this->TThread::Detach(); // linux 에서는 아주 중요한 코드이다. + + #ifdef _DEBUG + std::cout<<"▶▶ ZCThreadEx::Init(THelpKey1, THelpKey2), " + "THelpKey1 typename="< _VT_ void Exec(THelpKey AR_HelpKey) + { + #ifdef _DEBUG + std::cout<<"▶ ZCThreadEx::Exec(THelpKey), THelpKey typename="< _VT_ void Exec(THelpKey AR_HelpKey)*/ + + template + _VT_ void Exec(THelpKey1 AR_HelpKey1,THelpKey2 AR_HelpKey2) + { + #ifdef _DEBUG + std::cout<<"▶▶ ZCThreadEx::Exec(THelpKey1, THelpKey2), " + "THelpKey1 typename="< _VT_ void Fini(THelpKey) + { + #ifdef _DEBUG + std::cout<<"▶ ZCThreadEx::Fini(THelpKey), THelpKey typename="< _VT_ void Fini(THelpKey) */ + + template _VT_ void Fini(THelpKey1, THelpKey2) + { + #ifdef _DEBUG + std::cout<<"▶▶ ZCThreadEx::Fini(THelpKey1, THelpKey2), " + "THelpKey1 typename="< + + int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask); + int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask); + + void CPU_CLR (int cpu, cpu_set_t *set); + int CPU_ISSET(int cpu, cpu_set_t *set); + void CPU_SET (int cpu, cpu_set_t *set); + void CPU_ZERO ( cpu_set_t *set); + +■ 조건변수로 쓰레드를 대기시키거나 깨우는 동작을 구현할 때, 일반적으로 쓰레드가 잠자 + 고 있는지 동작중인지를 판단하는 변수와, 쓰레드를 재워야하는지 아닌지를 표시하는 변 + 수, 이렇게 2 개가 필요하다. + +■ 긴 작업을 하고 있는 쓰레드의 경우, 그 쓰레드가 현재 어디까지 작업을 하고 있는지 알 + 고 싶을 때가 있다. 이때 작업 진행 정보를 멤버 변수에 담아 두게 되는데, 다른 쓰레드 + 에서 이 진행 정보 멤버에 접근할 때, 해당 멤버 변수가 int 나 long 과 같은 primitive + 인 경우는 상관이 없으나 문자열 같은 동적버퍼를 가지고 있는 object 인 경우, 동적 버 + 퍼의 동시 접근 과정에서 오류가 발생할 수 있다. + + 이런 때는 '진행 정보'만을 별도로 담당하는 내포 클래스를 만들어서 해결하자. 이 '진행 + 정보' 용 내포클래스는 동기화 object 를 가지고 있고, 이 object 에 접근하는 코드는 동 + 기화 object 멤버를 통해서, 동기화 영역으로 묶어주어야 한다. 진행 정보가 다소 많다 + 고 생각될 경우, '진행 정보'를 Map 으로 구성하는 것도 좋다. + + 이런 목적에 딱 맞는 Map 클래스가 ZNsMain::CKeyValueMap_T<> 이다. + +■ 다수의 작업쓰레드에서 접근하는 설정 정보가 있고, 이 설정정보를 업데이트 하는 상황을 + 생각해보자. 이 설정 정보에는 동적할당 object 가 있어서 작업 쓰레드는 이 설정정 보가 + 업데이트 되는 동안에는, 이 정보에 접근하면 안된다. 그렇다고 매번 동기화 영역에서 설 + 정 정보가 업데이트 중인지 체크하는 것은 비합리적이므로 차라리 작업 쓰레드마다 설정 + 정보를 별도로 갖고 있는 것도 한 가지 방법일 듯 하다. 그래서 추가로 volatile 설정 정 + 보 업데이트 버전 변수를 하나 두고 계속 체크해서, 이 값이 변할 때만 동기화 영역에서 + 설정 정보를 업데이트하는 것이다. (물론 작업쓰레드 외부에 업데이트된 설정 정보가 이 + 미 존재해야 한다.) volatile 설정정보 업데이트 버전 변수를 두는 방법 이외에 설정 정 + 보를 업데이트하라는 표시를 가진 작업을 작업 쓰레드에 전달하는 것도 생각할 수 있다. + + -- 2009-12-23 00:24:00 + + '업데이트하라는 표시를 가진 작업을 작업쓰레드에 전달하는 것'이 아주 유력한 방법이 + 다. N 개의 쓰레드로 이루어진 쓰레드풀이라면 최소 N 개의 '업데이트 표시'를 작업 쓰레 + 드풀에 등록할 것이고, 풀의 각 작업 쓰레드가 이 '표시'를 작업큐에서 하나씩 꺼내와서, + 업데이트가 시작될 수 있음을 알게 되는 때부터는 설정 정보에 접근할 때, 반드시 동기화 + 영역에서 접근한다. N 개의 쓰레드 전부가 이 표시를 받았음을 확인했으면 그때 비로서 + 설정 정보 업데이트 작업을 (물론 동기화 영역에서) 진행한다. 이때 N 개의 각 작업 쓰레 + 드는 이미 동기화 영역에서 설정 정보에 접근하고 있으므로, 설정 정보 업데이트 작업은 + 안전하다. 업데이트 설정 작업이 끝났으면, 그 이후로는 각 작업 쓰레드는 비동기화 영역 + 에서 설정 정보에 접근할 수 있다. + + 이런 식의 처리에는 주의점이 있는데, 쓰레드풀의 작업 쓰레드가 작업큐에서, 1 개의 작 + 업이 아닌 N 개의 작업을 가지고 올때는 도데체 몇 개의 '업데이트 표시'를 쓰레드풀에 + 등록해야 할 것인지 고민이 필요하다. + + 다수의 작업 쓰레드에서 접근하는 설정 정보를 정확하게 업데이트하는, 이와 같은 멀티쓰 + 레딩 디자인 패턴을 + + Configuration State Change Pattern + + 이라고 부르자. + + -- 2010-08-19 23:59:00 + +■ 멀티쓰레딩 환경의 특정 작업쓰레드 모델에서 작업을 정의할 때, 작업 쓰레드에서 수행되 + 는 다수의 작업이 하나의 object 와 관련이 있고, 이 다수의 작업이 해당 object 의 멤버 + 에 접근해서 어떤 설정을 하는 경우, 게다가 이 설정 상태에 따라 object 에 관한 어떤 + 실행을 해야 하고(즉 그 object 의 특정 멤버 함수를 호출해야 하고), 그것도 동기화 영 + 역에서 해야 하는 경우, 해당 동기화 영역이 자칫 길어질 수 있다. 이를 방지하기 위해 + 해당 멤버함수의 수행을 비동기적으로(즉 별도의 작업쓰레드에서) 처리하는 것이 매우 좋 + 을 수 있다(이때 해당 object 가 해당 함수의 수행 전후로, 그 함수를 수행 중인지 아니 + 면 수행을 완료했는지를 나타내는 멤버 변수가 하나 필요하고 이 변수의 설정은 동기화 + 영역에서 이루어져야 한다. 그리고 일반적으로 이 멤버 변수가 '수행 중'임을 표시하면 + 다른 쓰레드에서 같은 object 에 대하여, 같은 함수의 수행을 막아야 한다). 해당 동기화 + 영역이 (특히 리눅스에서) 얼마나 비싼 구간인지, www.hemose.co.kr 의 주식 정보방 메신 + 저 서버의 작업쓰레드가 Dead Lock 에 빠지는 경험을 하면서 뼈져리게 느꼈다. + + -- 사실은 Dead Lock 보다는 무한 루프에 가까웠다. -- 2013-07-19 13:36:00 + + 아니면 특정 상태의 object 만을 처리하는 '작업'을 정의할 수도 있겠다. epoll 을 사용 + 하여 IOCP 를 구현할 때, '소켓 종료' 작업을 별도의 이벤트로 정의했었다. + + -- 2010-01-05 00:42:00 + + 그러고 보면 + + CSockInfo_BASE::OnInit(~) + + 는 상당히 초기에 동기화 영역 외부에서 + 호출하게 설계하였고, + + CSockInfo_BASE::OnRecvAll(~), + CSockInfo_BASE::OnSendAll(~) + + 은 상당히 나중에 비동기적 기법으로 동기화 영역 외부에서 호출하게 했고 + + CSockInfo_BASE::OnClose(~) + + 는 이제서야 비동기적 기법으로 동기화 영역 외부에서 호출하게 했다. 휴우~~ + + 여기까지 장장 3 년의 세월이 흐른 것 같다. !! + + -- 2010-01-05 12:52:00 + + + 3 년이나 지나서야 비동기적으로 처리해야 할 부분을 (사실상) 모두 처리했다라는게, 어 + 떻게 보면 암울할 수 있다. 그런데, CSockInfo_BASE::OnClose(~) 에 동기화 영역에서 수 + 행된다라는 약점을 확실하게 인식하지 못한채, 분산처리 등 복잡한 소프트웨어를 개발했 + 었더라면 더 큰일이 발생하지 않았을까. 또한 이 약점을 발견한 시점이 막 분산처리에 이 + 라이브러리를 사용하려는 시점이있고, 때마침 www.hemose.co.kr 의 주식정보방 서버가 먹 + 통(Dead Lock) 이 되는 바람에, 이를 조사하는 과정에서 발견한 것이므로 상당한 행운이 + 라고 봐야 한다. 음, 그렇다면 나폴레옹이 오스터리츠 승리 후에 내린 포고령에서처럼 + + "장병들이여! 나는 그대들에게 만족하노라." + + 나에게 행운을 선사한, 그래서 나를 지켜준 장병들에게 감사를 표현하고 싶다. + + -- 2010-01-10 16:14:00 + +■ 이 시점에서 멀티쓰레드 프로그래밍은 작업쓰레드 모델만 잘 설계하면 되는 줄 알았는데, + 그 이외에 '작업'을 설계하는 것도 아주 중요한 것임을 알았다. 즉 다수의 작업쓰레드에 + 서 수행되는 '작업' 이 동일한 object 에 대하여 '작업'을 하는 것이고, '작업' 진행 상 + 태에 따라, 해당 object 의 특정 '작업'은 동기화 영역에서 보호를 해주어야 할 때, 게 + 다다 이 동기화 영역이 다소 길어질 수 있을 때, 이 '작업'을 비동기적으로 처리하도록 + 설계하는 것이 아주 중요하다는 깨달음을 얻었다. + + 이런 경우, 비동기적으로 처리해야 하는 작업 마다 그 '작업'이 처리 중인지, 완료되었는 + 지를 나타내는 멤버변수가 하나 필요하고, 이 멤버 변수의 설정은 그 '작업'의 전후에서 + '동기화 영역'에서 수행되어야 하고, 이 변수가 '처리 중' 표시이면 다른 작업 쓰레드에 + 서 같은 object 에 대하여 같은 '작업' 의 수행을 (일반적으로) 막아야 한다. 그러면 비 + 동기적으로 수행했지만 동기화 영역에서 수행한 것과 같은 효과를 갖는 것이다. + + 이렇게 복잡한 상황은 좀처럼 없겠지만 IOCP 소켓 설계에서는 이처럼 복잡했다. + + -- 2010-01-05 13:10:00 + +■ 다시 한 번 정리하면 동기화 영역에서 호출되어야 하는 함수는 수행 시간이 정말 짧은 지 + 확인해야 한다. 만약 이 함수가 상속등의 이유로 재정의되고, 다소 긴 작업을 하게 된다면, + 이 함수의 수행을 비동기적으로 처리하는 것이 필수다. 동기화 영역에서 파일에 로그를 찍 + 는 것도 부담이 되는 작업이다. + + 멀티쓰레딩 관련 격언에 + + "항상 술어를 테스트하라! 그리고 다시 한 번 테스트하라!" + + 는 말이 있다(Posix 쓰레드를 이용한 프로그래밍, 124P, + 데이비드 R. 부트노프, 정보문화사). 여기에 다른 격언을 추가하면 + + "동기화 영역에서 수행되는 함수가 + 정말 빨리 수행을 마치는 지 확인하라!" + + -- 2010-01-05 19:26:00 + + + 상황을 정리할 겸, 이런 경우을 가정해보자. 작업 쓰레드풀 에서 수행되는 작업 클래스 + CSomeWork 와, 동기화 영역 sync1 에서 CSomeWork 을 처리하는 함수 + + func_sync_a (CSomeWork&) + func_sync_b1(CSomeWork&) + func_sync_b2(CSomeWork&) + + 그리고, 비동기화 영역에서 수행되는 함수 + + func_sync_not_b(CSomeWork&) + + 이 있다. 이 함수들은, CSomeWork 의 인스턴스 my_CSomeWork 에 대하여 + func_sync_b1(my_CSomeWork) 을 호출했다면 다음에는 반드시 func_sync_not_b() 와 + func_sync_b2() 를 순서대로 호출해야 한다. 즉 아래 호출 순서가 성립해야 한다. + + func_sync_b1 (my_CSomeWork) -- 함수1 + func_sync_not_b(my_CSomeWork) -- 함수2 + func_sync_b2 (my_CSomeWork) -- 함수3 + + func_sync_a(my_CSomeWork) 는 어디에서든지 호출될 수 있다. 이 상황에서 어떻게 '함수1' + 부터 '함수3' 까지의 호출 순서를 유지할 수 있을까. 쉽게 처리할 거면, func_sync_b1() + 부터 '함수3' 까지를 아예 같은 동기화 영역 sync1 에서 수행하는 것이다. + + (불행히도 이 경우, 만약 func_sync_not_b(my_CSomeWork) 가 func_sync_a(my_CSomeWork) 을 + 수행하는 경우, 같은 동기화 영역을 사용하고 있으므로 Dead Lock 에 빠질 수 있다.) + + 아니면 새로운 동기화 영역 sync2 에서 수행하게 하는 방법도 있다. 어느 방법이든지 func_ + sync_not_b() 가 매우 길어질 수 있는 작업을 하는 경우에는, 이 동기화 영역을 수행하고 있 + 는 쓰레드는 어쩔수 없이 다른 쓰레드의 진입을 막고 있을 수 밖에 없다. 이런 사태는 어쨌든 + 피해야 한다. + + 피하는 방법은 간단하다고 볼 수 있다. CSomeWork 에 이 클래스의 인스턴스가 func_sync_b1() + 를 수행하고 있는지, func_sync_b2() 을 수행하고 있는지를 나타내는 어떤 정수형 상태값 + mi_func_state 을 두고, func_sync_b1() 의 수행이 끝나는 부분에서, mi_func_state 멤버 + 에 func_sync_b1() 을 수행했다는 표시를 설정하고, 작업 쓰레드 풀에, my_CSomeWork 에 + 대하여 func_sync_not_b(my_CSomeWork) 와 func_sync_b2() 을 잇달아 수행하게 하는 어떤 + 표시를 등록하는 것이다. 막 등록을 마치고, 동기화 영역을 벗어나면, 설령 다른 쓰레드가 + my_CSomeWork 에 대하여 func_sync_b1(my_CSomeWork) 을 호출할려고 해도, 이미 my_CSomeWork. + mi_func_state 에, func_sync_b1() 의 수행을 완료하고, 곧바로 func_sync_not_b(my_CSomeWork) + 를 수행하려고 하고 있다는 표시가 들어있으므로, func_sync_b1(my_CSomeWork) 의 수행을 + 중지하고, 다른 CSomeWork 인스턴스에 대한 작업을 진행할 것이다. + + IOCP 소켓 관련 소스 CIOCP.H 나 CIOCPEPoll1.H, 혹은 + CSockInfo_BASE_Win.H 나 CSockInfo_BASE_Linux.H 등에서 + + CSockInfo_BASE_T<>::OnInit() + CSockInfo_BASE_T<>::OnRecvAll() + CSockInfo_BASE_T<>::OnSendAll() + CSockInfo_BASE_T<>::OnClose() + + 함수를 참고하면 된다. 이와 같이 해결하는 멀티쓰레딩 디자인 패턴을 + + Sequential Sync Pattern + + 이라고 부르자. + + -- 2010-08-19 23:59:00 + +■ 헤모스(www.hemose.co.kr) 실시간 주식 정보방 메신저 서버가 갑자기 먹통이 되는 사태를 + 처리하면서, CSockInfo::OnClose(~) 를 비동기적으로 호출하는 것, 그리고 다른 약간의 + 오류 수정 및 몇몇 최적화 작업 이외에, 중대한 버그를 하나 잡아냈는데, CNetBuffSend_T + <>::Fini() 함수에서 송신버퍼 리스트를 초기화하는데, + + for(int i=0;mo_CNetBuffSendList.size();++i) + { + // some code + } + + 처럼 되어 있었다. 원래는 + + for(int i=0;i +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace ZNsMain +{ + + /*//////////////////////////////////////////////////////////////////////// + + κ Լ ϸ 0 ȯϴµ enum Ѵ. + + ////////////////////////////////////////////////////////////////////////*/ + + namespace ZNsEnum + { + + // Լ 쿡 å , ZEThread_Invalid ̿ ȯ ִ. + + enum ZEThread + { + ZEThread_OK =0 , + ZEThread_Invalid=EINVAL , // Լ . + ZEThread_TimeOut=ETIMEDOUT + };/* + enum ZEThread*/ + + + /*//////////////////////////////////////// + + barrier ǥ ȯ. + + barrier üũ + + BarrierClass VO_BarrierClass; + + if(VO_BarrierClass.Init()==ZEBarrier_NO) + { + // some code + } + + . + + if(VO_BarrierClass.Init()!=ZEBarrier_OK) + { + // some code + } + + ؾ ϴ. + + ////////////////////////////////////////*/ + + enum ZEBarrier + { + ZEBarrier_NO = -1, + ZEBarrier_OK = 0 + };/* + enum ZEBarrier*/ + + }/* + namespace ZNsEnum*/ + + + /*///////////////////////////////////////////////////////////////////////////////////// + + pthread ̺귯 ũ ɾ . + + 3.0 sys/sem.h ִ. + + The user should define a union like the following to use it for arguments + for `semctl'. + + union semun + { + int val; <= value for SETVAL + struct semid_ds *buf; <= buffer for IPC_STAT & IPC_SET + unsigned short int *array; <= array for GETALL & SETALL + struct seminfo *__buf; <= buffer for IPC_INFO + }; + + Previous versions of this file used to define this union but this is + incorrect. One can test the macro _SEM_SEMUN_UNDEFINED to see whether + one must define the union or not. + + #define _SEM_SEMUN_UNDEFINED 1 + + IPC object ÷״ IPC_CREAT, IPC_EXCL, 0 ϳ̸, 0 ̸ ش + ȭ object . + + Ͽ ִ Լ μ 쿡 ʰ ִ. + ׷ μ 쿡 Լ Ѵ. + + -- 2004-07-12 + + /////////////////////////////////////////////////////////////////////////////////////*/ + + union semun + { + int val ; // value for SETVAL + struct semid_ds* buf ; // buffer for IPC_STAT & IPC_SET + unsigned short int* array; // array for GETALL & SETALL + struct seminfo* __buf ; // buffer for IPC_INFO + };/* + union semun*/ + + + /*////////////////////////////////////////////////////////////////// + + 쿡 ȭ object ̸ ο ִµ, + Ű ο ִ. ׷ ȣȯ Ͽ ̸κ + Ű ϴ Լ . ̸ ȴٸ ftok() Լ + + key_t ftok(const char *path, int id); + + ϴ ͵ ̴. + + //////////////////////////////////////////////////////////////////*/ + + static inline long ZfGetKeyNum(const char* const AP_Name) + { + int VI_Index =-1 ; + long VL_KeyID = 1 ; + + if(AP_Name!=0) + { + while(AP_Name[++VI_Index]!=0) + { + VL_KeyID += AP_Name[VI_Index]*(VI_Index+1) ; + }/* + while(AP_Name[++VI_Index]!=0)*/ + }/* + if(AP_Name!=0)*/ + + return VL_KeyID; + }/* + static inline long ZfGetKeyNum(const char* const AP_Name)*/ + + + /*///////////////////////////////////////////////////////////////////////////// + + ñ׳ ʴ´. ̺Ʈ ̾ ټ ߻ߴٰ ؼ + μ ñ׳ ټ ʴ´. ̷ + sa_mask ذ ִ. sa_mask ñ׳ε ̺Ʈ + ̼ ټ ߻ϴ ñ׳ ߻Ų. ù° ñ + óǴ ñ׳ε ŷ ¿ ְ ȴ. + + -- TCP/IP α׷ ( ) 245 Page + + ߿ Ansi, Posix ñ׳ + + #define SIG_ERR ((__sighandler_t) -1) // Error return. + #define SIG_DFL ((__sighandler_t) 0) // Default action. + #define SIG_IGN ((__sighandler_t) 1) // Ignore signal. + + #define SIGHUP 1 // Hangup (POSIX) + #define SIGINT 2 // Interrupt (ANSI) + #define SIGQUIT 3 // Quit (POSIX) + #define SIGILL 4 // Illegal instruction (ANSI) + #define SIGTRAP 5 // Trace trap (POSIX) + #define SIGABRT 6 // Abort (ANSI) + #define SIGFPE 8 // Floating-point exception (ANSI) + #define SIGKILL 9 // Kill, unblockable (POSIX) + #define SIGUSR1 10 // User-defined signal 1 (POSIX) + #define SIGSEGV 11 // Segmentation violation (ANSI) + #define SIGUSR2 12 // User-defined signal 2 (POSIX) + #define SIGPIPE 13 // Broken pipe (POSIX) + #define SIGALRM 14 // Alarm clock (POSIX) + #define SIGTERM 15 // Termination (ANSI) + #define SIGSTKFLT 16 // Stack fault + #define SIGCHLD 17 // Child status has changed (POSIX) + #define SIGCONT 18 // Continue (POSIX) + #define SIGSTOP 19 // Stop, unblockable (POSIX) + #define SIGTSTP 20 // Keyboard stop (POSIX) + #define SIGTTIN 21 // Background read from tty (POSIX) + #define SIGTTOU 22 // Background write to tty (POSIX) + #define SIGSYS 31 // Bad system call + #define SIGUNUSED 31 + + SIGHUP + + - ͹̳ ̽ Ǹ ش ͹̳ΰ μ( ) + - ߻ϴµ ̶ foreground μ ׷쳻 μ鿡 + - SIGHUP ñ׳ ø ߻ϴ ñ׳̴. + - ̸ ִ ý SIGHUP ñ׳ configure file ٽ о̴ ʱȭ ȣ ؼѴ. + . bootp(8), gated(8), inetd(8), mountd(8), named(8), nfsd(8), ypbind(8) + . pppd(8) ó SIGHUP ǵ ϰ ޾Ƶ̴ ʵ Ȥ ִµ, SIGTERM ô´. + . daemon ܸ kernelκ SIGHUP ȣ Ѵ. + ׷Ƿ daemon ȣ daemon Ǿ daemon о ȴٴ ˷ִ ڷκ Ѵ. + . daemon ٸ ȣ SIGINT SIGWINCH ְ ̵鵵  ȭ daemon ϱ ִ. + + SIGINT + + - ͷƮ Ű (DELETE Ǵ Control-C) ߻ + + SIGQUIT + + - Control-backslash ߻ + + SIGCHLD + + - μ ϰų ϸ, θ μ ޵ȴ. + - θ μ wait() ý Ͽ Ͼ ˾ƺ. + - ñ׳ο default ó ϴ ̴. μ ȣ ޵ȴ. + + SIGSEGV + + - ȿ ޸ ּҸ ϰų ޸𸮿 μ ޵ȴ. + + SIGTERM + + - kill ɿ ⺻ ߻ + + SIGKILL + + - "ش ġ(extreme prejudice)" α׷ ϴ ȴ. + - ñ׳ catch ϰų . + + SIGALRM + + - alarm()̳ setitimer() ý ݷ ˶ ð ʰ μ ޵ȴ. + + SIGTSTP + + - Control-Z Ű ߻ + - ⺻ ó SIGCONT ȣ μ ߴѴ. + + SIGCONT + + - μ Ű ߻ + - ȣ ϰų . + - ⺻ ó ߴܵ μ ϴ ̴. ׷ μ ȣ ʴ´ٸ ȣ . + - vi ͸ + . Control-Z Ű Ű Է óϰ Ǵµ + . ̶ fg Ű vi SIGCONT ñ׳ ϸ + . vi ñ׳ο ó ȭ ٽ ׸ Ű Է ޴ · ư. + + SIGSTOP + + - SIGTSTP ϳ catch ϰų . + - ȣ SIGCONT ȣ μ ߴѴ. + + SIGABRT + + - abort() Լ ȣ ߻ + + SIGBUS + + - ϵ ߻ + + SIGEMT + + - ϵ ߻ + + SIGFPE + + - divide-by-0 ε Ҽ ÷ο ߻ + + SIGILL + + SIGINFO + + SIGIO + + SIGIOT + + SIGPIPE + + - pipe ſ μ ۽ μ write ϸ ߻ + - μ RST Ͽ ͸ , Ŀ μ ISGPIPE ȣ . + - ȣ ⺻ μ Ű ̹Ƿ, μ ʴ Ḧ ϱ ؼ ȣ ؾ Ѵ. + + SIGPOLL + + SIGROF + + SIGPWR + + SIGSYS + + SIGTTIN + + - background ִ μ ͹̳ηκ б⸦ õѴ. + + SIGTTOU + + - background ִ μ ͹̳ηκ ⸦ õѴ. + + SIGURG + + - SIGIO SIGURG ȣ F_SETOWN ֿ ҴǾ Ͽ ߻Ѵ. + + SIGUSR1 + + SIGUSR2 + + SIGVTALRM + + SIGWINCH + + SIGXCPU + + SIGXFSZ + + -- 2009-11-29 00:26:00 + + linux sigaction -- 2011-06-05 22:55:00 + + struct sigaction { + union { + __sighandler_t _sa_handler; + void (*_sa_sigaction)(int, struct siginfo *, void *); + } _u; + sigset_t sa_mask ; + unsigned long sa_flags; + void (*sa_restorer)(void); + }; + + #define sa_handler _u._sa_handler + #define sa_sigaction _u._sa_sigaction + + solaris sigaction -- 2011-06-05 22:56:00 + + struct sigaction { + int sa_flags; + union { + #ifdef __cplusplus + void (*_handler)(int); + #else + void (*_handler)(); + #endif + #if defined(__EXTENSIONS__) || defined(_KERNEL) || \ + (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) || \ + (_POSIX_C_SOURCE > 2) || defined(_XPG4_2) + void (*_sigaction)(int, siginfo_t *, void *); + #endif + } _funcptr; + sigset_t sa_mask; + #ifndef _LP64 + int sa_resv[2]; + #endif + }; + + #define sa_handler _funcptr._handler + #define sa_sigaction _funcptr._sigaction + + freebsd sigaction -- 2011-06-05 22:59:00 + + struct sigaction { + union { void (*__sa_handler)(int); + void (*__sa_sigaction)(int, struct __siginfo *, void *); + } __sigaction_u; // signal handler + int sa_flags; // see signal options below + sigset_t sa_mask; // signal mask to apply + }; + + #define sa_handler __sigaction_u.__sa_handler + + /////////////////////////////////////////////////////////////////////////////*/ + + + class ZCSigAction : public sigaction + { + public: + typedef struct sigaction StSigAction; + public: + + ZCSigAction() + { + ::memset((sigaction*)this, 0, sizeof(StSigAction)); + }/* + ZCSigAction()*/ + + StSigAction& GetBaseObj() + { + return (StSigAction&)(*this); + }/* + StSigAction& GetBaseObj()*/ + + void SetFlags(int AI_Flags) + { + this->sa_flags=AI_Flags; // RTS SA_SIGINFO + }/* + void SetFlags(int AI_Flags)*/ + + void SetHandler(void (*APF_Handler)(int)) + { + this->sa_handler=APF_Handler; + }/* + void SetHandler(void (*APF_Handler)(int))*/ + + void SetHandlerEx(void (*APF_Handler)(int, siginfo_t*, void*)) + { + this->sa_sigaction=APF_Handler; // ַ RTS + }/* + void SetHandlerEx(void (*APF_Handler)(int, siginfo_t*, void*))*/ + + bool EmptySet() + { + return sigemptyset(&this->sa_mask)==0 ; + }/* + bool EmptySet()*/ + + bool FillSet() + { + return sigfillset(&this->sa_mask)==0 ; + }/* + bool FillSet()*/ + + bool CutSet(int AI_SigNo) + { + return sigdelset(&this->sa_mask, AI_SigNo)==0 ; + }/* + bool CutSet(int AI_SigNo)*/ + + bool AddSet(int AI_SigNo) + { + return sigaddset(&this->sa_mask, AI_SigNo)==0 ; + }/* + bool AddSet(int AI_SigNo)*/ + + bool Act(int AI_SigNum, struct sigaction* AP_OldSigAction=0) + { + return ::sigaction(AI_SigNum, this, AP_OldSigAction)==0 ; + }/* + bool Act(int AI_SigNum, struct sigaction* AP_OldSigAction=0)*/ + + + static ZTypUInt Alarm(ZTypUInt AI_Sec) + { + return ::alarm(AI_Sec); + + /* AI_Sec 0 ˶ û . ˶ ȣ + ޵DZ ִ ð ȯϰų ȣ + ϸ -1 ȯѴ. */ + }/* + static ZTypUInt Alarm(ZTypUInt AI_Sec)*/ + + static bool Kill(int AI_SigNo, pid_t AI_Pid=::getpid()) + { + return ::kill(AI_Pid, AI_SigNo)==0 ; + }/* + static bool Kill(int AI_SigNo, pid_t AI_Pid=::getpid())*/ + + + #ifdef __linux__ + + /*///////////////////////////////////////////////////////////////////////// + + freebsd 8.2, solaris 5.11 F_SETSIG ǰ Ǿ ʾƼ, + Ʒ SetupRTS() Լ . RTS . + + -- 2011-06-09 04:25:00 + + /////////////////////////////////////////////////////////////////////////*/ + + // ַ SIGRTMIN ~ SIGRTMAX ̿ ִ RTS Ѵ. + + static bool SetupRTS(int AI_FileID, int AI_SigNo=SIGRTMIN, int AI_Flag=O_RDWR | /*O_NONBLOCK|*/O_ASYNC, pid_t AI_PId=::getpid()) + { + if (::fcntl(AI_FileID, F_SETFL, AI_Flag) < 0) + { + return false; + } + if (::fcntl(AI_FileID, F_SETSIG, AI_SigNo) < 0) + { + return false; + } + if (::fcntl(AI_FileID, F_SETOWN, AI_PId) < 0) + { + return false; + }/* + if (::fcntl(AI_FileID, F_SETOWN, AI_PId) < 0)*/ + + return true; + }/* + static bool SetupRTS(int AI_FileID, int AI_SigNo=SIGRTMIN, int AI_Flag=O_RDWR | O_NONBLOCK| O_ASYNC, int pid_t=::getpid())*/ + + #endif //__linux__ + + + public: + };/* + class ZCSigAction*/ + + + class ZCSigSet + { + private: + ::sigset_t mi_SigSet; + public : + + ::sigset_t& GetSigSet() + { + return mi_SigSet; + }/* + ::sigset_t& GetSigSet()*/ + + bool Empty() + { + return ::sigemptyset(&mi_SigSet)==0; + }/* + bool Empty()*/ + + bool Fill() + { + return ::sigfillset(&mi_SigSet)==0; + }/* + bool Fill()*/ + + bool Add(int AI_SigNo) + { + return ::sigaddset(&mi_SigSet, AI_SigNo)==0; + }/* + bool Add(int AI_SigNo)*/ + + bool Cut(int AI_SigNo) + { + return ::sigdelset(&mi_SigSet, AI_SigNo)==0; + }/* + bool Cut(int AI_SigNo)*/ + + bool IsMember(int AI_SigNo) + { + return ::sigismember(&mi_SigSet, AI_SigNo)==1; + }/* + bool IsMember(int AI_SigNo)*/ + + bool ProcMask(int AI_How, sigset_t* AP_OldSigSet=0) + { + return ::sigprocmask(AI_How, &mi_SigSet, AP_OldSigSet)==0; + }/* + bool ProcMask(int AI_How, sigset_t* AP_OldSigSet=0)*/ + + /*////////////////////////////////////////////////////////////// + + int AI_How ִ . + + SIG_BLOCK + The set of blocked signals is the union of the current + set and the set argument. + + ñ׳ ũ ñ׳ ũ ߰Ѵ. + ϵ ñ׳ ش ñ׳ ߻, ñ׳ + 鷯 Ϸ ȴ. + + ϵ ñ׳̶, ش ñ׳ ߻, + ñ׳ ڵ鷯 ϴٰ, ٸ ñ׳ ߻ϸ, + ϰ, ñ׳ ڵ鷯 Ŀ, + ϰ ȴ. + + SIG_UNBLOCK + The signals in set are removed from the current set of + blocked signals. It is legal to attempt to unblock a + signal which is not blocked. + + ñ׳ ũ ñ׳ ũ Ѵ. + + SIG_SETMASK + The set of blocked signals is set to the argument set. + + -- 2011-06-09 21:37:00 + + //////////////////////////////////////////////////////////////*/ + + + bool Wait(int& ARRI_SigNo) + { + return ::sigwait(&mi_SigSet, &ARRI_SigNo)==0; + }/* + bool Wait(int& ARRI_SigNo)*/ + + int WaitInfo(siginfo_t& ARR_StSigInfo) + { + return ::sigwaitinfo(&mi_SigSet, &ARR_StSigInfo); + }/* + int WaitInfo(siginfo_t& ARR_StSigInfo)*/ + + /*////////////////////////////////////////////////////////////////// + + SYNOPSIS + + #include + + int sigwaitinfo(const sigset_t *restrict set, + siginfo_t *restrict info); + + int sigtimedwait( const sigset_t *restrict set , + siginfo_t *restrict info, + const struct timespec *restrict timeout); + + RETURN VALUES + + Upon successful completion (that is, one of the signals + specified by set is pending or is generated) sigwaitinfo() + and sigtimedwait() will return the selected signal number. + Otherwise, the function returns -1 and sets errno to indi- + cate the error. + + ERRORS + + The sigwaitinfo() and sigtimedwait() functions will fail if: + + EINTR The wait was interrupted by an unblocked, caught + signal. + + ENOSYS The sigwaitinfo() and sigtimedwait() functions are + not supported. + + The sigtimedwait() function will fail if: + + EAGAIN No signal specified by set was generated within + the specified timeout period. + + The sigwaitinfo() and sigtimedwait() functions may fail if: + + EFAULT The set, info, or timeout argument points to an + invalid address. + + The sigtimedwait() function may fail if: + + EINVAL The timeout argument specified a tv_nsec value + less than zero or greater than or equal to 1000 + million. The system only checks for this error if + no signal is pending in set and it is necessary to + wait. + + -- 2011-06-02 01:14:00 + + //////////////////////////////////////////////////////////////////*/ + + + static bool AddInfo(int AI_SignalNo, const union sigval AI_SigVal, int AI_ProcessID=::getpid()) + { + return ::sigqueue(AI_ProcessID, AI_SignalNo, AI_SigVal)==0; + }/* + static bool AddInfo(int AI_SignalNo, const union sigval AI_SigVal, int AI_ProcessID=::getpid())*/ + + /*////////////////////////////////////////////////////////////////// + + SYNOPSIS + + #include + #include + + union sigval{int sival_int; void* sival_ptr;}; + + int sigqueue(pid_t pid, int signo, const union sigval value); + + RETURN VALUES + + Upon successful completion, the specified signal will have + been queued, and the sigqueue() function returns 0. Other- + wise, the function returns -1 and sets errno to indicate the + error. + + ERRORS + + The sigqueue() function will fail if: + + EAGAIN No resources are available to queue the signal. + The process has already queued SIGQUEUE_MAX sig- + nals that are still pending at the receiver(s), + or a system wide resource limit has been + exceeded. + + EINVAL The value of signo is an invalid or unsupported + signal number. + + ENOSYS The sigqueue() function is not supported by the + system. + + EPERM The process does not have the appropriate + privilege to send the signal to the receiving + process. + + ESRCH The process pid does not exist. + + -- 2011-06-02 01:40:00 + + //////////////////////////////////////////////////////////////////*/ + + public: + };/* + class ZCSigSet*/ + + + + class ZCProcess + { + public: + + // cf) typedef int pid_t + + // 뵵ε Լ̴. + + bool Exec(const char* AP_ExeName, bool AB_DoCloseStdInOut=true) + { + return this->Exec(AP_ExeName, NULL, AB_DoCloseStdInOut); + }/* + bool Exec(const char* AP_ExeName, bool AB_DoCloseStdInOut=true)*/ + + bool Exec(const char* AP_ExeName, char* const APA_Arg[], bool AB_DoCloseStdInOut=true) + { + /*///////////////////////////////////////////////////////////////// + + APA_Arg Ҵ NULL Ѵ. + + char *aRgu[4]; + + aRgu[0] = "/test/test.exe"; + aRgu[1] = "ABC"; // Argu 1 + aRgu[2] = "10" ; // Argu 2 + aRgu[3] = 0 ; // ƱԸƮ ̶ ͸ Ͽ Ѵ. + + execvp(aRgu[0] , aRgu); + + execl + + ::execl( "./WinSEC_D.exe" , + "./WinSEC_D.exe" , + "WinSEC_Conf.txt", + NULL + ////// ); + + /////////////////////////////////////////////////////////////////*/ + + if(AP_ExeName==0 || AP_ExeName[0]==0) return false; + + int VI_ForkNum = ::fork(); /*####################*/ + + if(VI_ForkNum==0) // child + { + if(AB_DoCloseStdInOut==true) + { + ::close(0); + ::close(1); + }/* + if(AB_DoCloseStdInOut==true)*/ + + ::setsid(); // ڱ ڽ . + ::execvp(AP_ExeName, APA_Arg); + + return true; + } + else if(VI_ForkNum==-1) // error + { + return false; + } + else // θ + { + return true; + }/* + else*/ + }/* + bool Exec(const char* AP_ExeName, char* const APA_Arg[], bool AB_DoCloseStdInOut=true)*/ + + static pid_t Fork (){return ::fork ();} + static int GetPPID(){return ::getppid();} + static int GetUID (){return ::getuid ();} + static int GetGID (){return ::getgid ();} + static long GetPID (){return ::getpid ();} + + public: + };/* + class ZCProcess*/ + + + class ZCMemMap + { + public: + + static void* LinkMap( + int AI_FileDesc, off_t AL_Offset=0, size_t AL_MapSize=0, int AI_Protect=PROT_READ | PROT_WRITE, int AI_Flags=MAP_SHARED, void* AP_BaseAddress=NULL) + { + return ::mmap(AP_BaseAddress, AL_MapSize, AI_Protect, AI_Flags, AI_FileDesc, AL_Offset); + }/* + static void* LinkMap( + int AI_FileDesc, off_t AL_Offset=0, size_t AL_MapSize=0, int AI_Protect=PROT_READ | PROT_WRITE, int AI_Flags=MAP_SHARED, void* AP_BaseAddress=NULL) */ + + /* munmap(void*,size_t) + + Upon successful completion, munmap() returns 0. Otherwise, + it returns -1 and sets errno to indicate the error */ + + static bool UnMap(void* AP_BaseAddress, size_t AL_Size) + { + return ::munmap(AP_BaseAddress, AL_Size)==0; + }/* + static bool UnMap(void* AP_BaseAddress, size_t AL_Size)*/ + + public: + };/* + class ZCMemMap*/ + + + /*///////////////////////////////////////////////////////////////////////////// + + SHMGET(2) α׷ ޴ SHMGET(2) + + ̸ + + shmget - ޸ ׸Ʈ ҴѴ. + + + + #include + #include + + int shmget(key_t key, int size, int shmflg); + + + shmget() key ڰ õ ޸ ׸Ʈ ĺڸ ȯѴ. + , key IPC_PRIVATE ְų Ǵ key IPC_PRIVATE + ϰ, key Ǿ ִ ޸ ׸Ʈ ٸ PAGE_SIZE + ŭ size ִ ο ޸ ׸Ʈ + . IPC_CREAT shmflg õǾ ִ. (i.e. shmflg&IPC_CREAT + 0 ƴϴ.) + + shmflg : + + IPC_CREAT ο ׸Ʈ . ÷װ ʴ + , shmget() key õ ׸Ʈ ã ̸, + ׸Ʈ õ shmid 㰡 ִ + ؼ ˻Ѵ. ׸ ׸Ʈ ıǾٴ ǥø + ʵ Ѵ. + + IPC_EXCL ׸Ʈ Ұ и ϱ IPC_CREAT Բ + ȴ. + + mode_flags (lowest 9 bits) + , ׷, ܵ ϱ 㰡 Ѵ. + , 㰡 ýۿ ʴ´. + + ο ׸Ʈ ȴٸ, shmflg 㰡׸Ʈ + ִ shmid_ds shm_perm ȴ. shmid_ds ü: + + struct shmid_ds { + struct ipc_perm shm_perm; // ۹̼ + int shm_segsz; // ׸Ʈ ũ(bytes) + time_t shm_atime; // ð + time_t shm_dtime; // ð + time_t shm_ctime; // ð + unsigned short shm_cpid; // pid + unsigned short shm_lpid; // ۵ μ pid + short shm_nattch; // μ + }; + + + struct ipc_perm + { + key_t key; + ushort uid; // euid egid + ushort gid; + ushort cuid; // euid egid + ushort cgid; + ushort mode; // shmflg 9Ʈ + ushort seq; // (sequence number) + }; + + Դٰ, Ǵ ý ý ޸ ׸Ʈ + shmid_ds ʱȭѴ. + + shm_perm.cuid shm_perm.uid ȣ μ ȿ user-ID + ȴ. + + shm_perm.cgid shm_perm.gid ȣ μ ȿ group-ID + ȴ. + + shm_perm.mode 9Ʈ shmflg 9Ʈ + . + + shm_segsz size ȴ. + + shm_lpid, shm_nattch, shm_atime ׸ shm_dtime 0 + ȴ. + + shm_ctime ð ȴ. + + ޸ ׸Ʈ ̹ Ѵٸ, 㰡 Ǹ, + ǥõǾ ִ ˾ƺ ˻Ѵ. + + SYSTEM CALLS + + fork() fork() Ŀ ڽ μ ޸ ׸Ʈ + Ѵ. + + exec() exec() Ŀ ޸ ׸Ʈ иȴ.(ı + ° ƴϴ) + + exit() exit() ޸ ׸Ʈ иȴ.(ıǴ + ƴϴ) + + ȯ + + ȿ ׸Ʈ ĺ shmid ȯǸ, -1 ȯ . + + + + н, errno ϳ ȴ: + + EINVAL SHMMIN > size, Ǵ size > SHMMAX, Ǵ size ׸ + Ʈ ũ⺸ ũٸ ̿ ȯȴ. + + EEXIST IPC_CREAT | IPC_EXCL Ǿ ְ, + ׸Ʈ ȯȴ. + + EIDRM ׸Ʈ ı ŵǵ ǥõǾ ִٸ ȯȴ. + + ENOSPC ޸ id (SHMMNI) ų û size + ׸Ʈ Ҵ ý ü ޸ Ѱ (SHMALL) ʰҰ ȯȴ. + + ENOENT ־ key شϴ ׸Ʈ ʰ, + IPC_CREAT ʾҴٸ ȯȴ. + + EACCES ڰ ޸ ׸Ʈ 㰡 ȯȴ. + + ENOMEM ׸Ʈ Ҵ ޸𸮰 ȯȴ. + + + + IPC_PRIVATE ÷ ʵ尡 ƴ϶ key_t Ÿ̴. Ư key + ȴٸ, ý shmflg 9Ʈ Ѵ. + ׸ ޸ ׸Ʈ ()Ѵ. + + shmget ý ݿ ִ ޸ ׸Ʈ ڿ Ѱ̴: + + SHMALL ý ü ޸ ׸Ʈ ִ : å ̴. + SHMMAX ޸ ׸Ʈ ִ ũ(Ʈ): ̴.( 4M) + SHMMIN ޸ ׸Ʈ ּ ũ(Ʈ): ̴. + (PAGE_SIZE ȿ ּ ũ, 1byte̴.) + SHMMNI ý ü ޸ ׸Ʈ ִ : ̴( 4096) + + μ ޸ ׸Ʈ Ư . (SHMSEG) + + /////////////////////////////////////////////////////////////////////////////*/ + + + // ޸ Ŭ + + class ZCShareMemory + { + private: + enum{EInvalidID=-1}; + private: + ZTypeID mh_FileMap; + void* mp_Address; + public : + + ZCShareMemory() + { + mh_FileMap= EInvalidID; + mp_Address= 0 ; + }/* + ZCShareMemory()*/ + + ZTypeID GetID() const + { + return mh_FileMap; + }/* + ZTypeID GetID() const*/ + + bool IsValidID() const + { + return mh_FileMap != -1; + }/* + bool IsValidID() const*/ + + void* GetStartAddress() const + { + return mp_Address; + }/* + void* GetStartAddress() const*/ + + bool Create(const char* AP_MapName, long AL_MapSize, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) + { + return Create((key_t)(ZNsMain::ZfGetKeyNum(AP_MapName)), AL_MapSize, AI_Flag); + }/* + bool Create(const char* AP_MapName, long AL_MapSize, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664)*/ + + bool Create(long AL_MapID, long AL_MapSize, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) + { + if((mh_FileMap=::shmget((key_t)AL_MapID, AL_MapSize, AI_Flag))==-1) + { + if(errno==EEXIST) + { + return (mh_FileMap=::shmget(AL_MapID, 0, 0)) != -1; + }/* + if(errno==EEXIST)*/ + + return false; + }/* + if((mh_FileMap=::shmget((key_t)AL_MapID, AL_MapSize, AI_Flag))==-1)*/ + + return true; + }/* + bool Create(long AL_MapID, long AL_MapSize, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664)*/ + + + bool ShmGet(const char* AP_MapName, long AL_MapSize, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) + { + return (mh_FileMap=::shmget((key_t)(ZNsMain::ZfGetKeyNum(AP_MapName)), AL_MapSize, AI_Flag))!=-1 ; + }/* + bool ShmGet(const char* AP_MapName, long AL_MapSize, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664)*/ + + bool ShmGet(const char* AP_MapName) + { + return (mh_FileMap=::shmget((key_t)(ZNsMain::ZfGetKeyNum(AP_MapName)), 0 ,0))!=-1 ; + }/* + bool ShmGet(const char* AP_MapName)*/ + + bool ShmGet(long AL_MapID, long AL_MapSize, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) + { + return (mh_FileMap=::shmget((key_t)AL_MapID, AL_MapSize, AI_Flag))!=-1 ; + }/* + bool ShmGet(long AL_MapID, long AL_MapSize, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664)*/ + + bool ShmGet(long AL_MapID) + { + // key AL_MapID ޸𸮰 ִ + + return (mh_FileMap=::shmget((key_t)AL_MapID, 0, 0))!=-1 ; + }/* + bool ShmGet(long AL_MapID)*/ + + + bool LinkMap() + { + // void *shmat(int shmid, const void *shmaddr, int shmflg); + + return (mp_Address=::shmat(mh_FileMap, (void*)0, 0))!=NULL ; + + // shmat() 3 ° μ SHM_RDONLY ÷׸ ϸ + // ޸ ׸Ʈ εǾ, б(readonly) ǥõȴ + }/* + bool LinkMap()*/ + + bool UnMap() + { + // cf) In Window : BOOL UnmapViewOfFile(LPCVOID lpBaseAddress); + + bool VB_IsOK=(::shmdt(mp_Address)!=-1); mp_Address=0; return VB_IsOK; + }/* + bool UnMap()*/ + + bool Close() + { + bool VB_IsOK=(::shmctl(mh_FileMap, IPC_RMID, 0)!=-1) ; + + mh_FileMap=EInvalidID; return VB_IsOK; + + /* IPC_RMID ɾ Ŀη ׸Ʈ ϴ ƴϴ. + ϱ ׸Ʈ ǥø صд. ü ׸Ʈ + پ ִ(attached) μ и(detached) Ͼ. + , ׸Ʈ پִ (attached) μ , Ŵ + ̷ . */ + }/* + bool Close()*/ + + public: + };/* + class ZCShareMemory*/ + + + /*//////////////////////////////////////////////////////////////////////////////////////// + + class ZCProcessMutex μ ؽ. + + Window ̸ִ mutex , Linux  ִ. + pthread ̺귯 Ἥ ޸𸮿 mutex Ÿ ־ ׸ŭ ܼ + ʿϴ. + + Linux ߾忡 μ  ٸ. + Ȯ pthread μ  ʴ´. (2006-12-28 16:02:00) + + ////////////////////////////////////////////////////////////////////////////////////////*/ + + class ZCProcessMutex + { + private: + ZTypeID mh_Mutex; + private: + + bool Init(int AI_InitNum=1) + { + // + // ʱȭѴ. + + union semun SemUnion; SemUnion.val=AI_InitNum; + + return ::semctl(mh_Mutex, 0, SETVAL, SemUnion)!=-1 ; + + /*////////////////////////////////////////////////////////// + + int semctl(int semid, int semnum, int cmd, ...) + + If successful, the value returned by semctl() depends on cmd as follows: + GETVAL + The value of semval. + GETPID + The value of sempid. + GETNCNT + The value of semncnt. + GETZCNT + The value of semzcnt. + All others + 0. + Otherwise, semctl() returns -1 and errno indicates the error + + //////////////////////////////////////////////////////////*/ + }/* + bool Init(int AI_InitNum=1)*/ + + /*private:*/ + public : + + ZCProcessMutex() + { + mh_Mutex=0; + }/* + ZCProcessMutex()*/ + + ZTypeID GetHandle() const + { + return mh_Mutex; + }/* + ZTypeID GetHandle() const*/ + + + // Linux μ Window μ ؽ Ѵ. + // Window ؽ μ Linux + // 쿡 ׷ ʴ. 2006-08-06 15:55:00 + + bool Make(const char* AP_MutexName, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) + { + return this->Make(ZNsMain::ZfGetKeyNum(AP_MutexName), AI_Flag); + }/* + bool Make(const char* AP_MutexName, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664)*/ + + bool Make(long AL_KeyID, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) + { + // AI_Flag IPC_CREAT,IPC_EXCL,0 ϳ̸ + // 0 ̸ ش ȭobject . + + // int semget(key_t key,int nsems,int semflg) + + if((mh_Mutex=::semget((key_t)AL_KeyID, 1, AI_Flag))==-1) + { + if(errno==EEXIST) + { + return (mh_Mutex=::semget((key_t)AL_KeyID, 1, 0)) != -1; + }/* + if(errno==EEXIST)*/ + + return false; + }/* + if((mh_Mutex=::semget((key_t)AL_KeyID, 1, AI_Flag))==-1)*/ + + this->Init(); return true; + }/* + bool Make(long AL_KeyID, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664)*/ + + bool Lock() + { + struct sembuf sembuf_Obj; + sembuf_Obj.sem_num= 0; // semaphore 迭 ° semaphore + sembuf_Obj.sem_op =-1; + sembuf_Obj.sem_flg=SEM_UNDO; + + return ::semop(mh_Mutex, &sembuf_Obj, 1)==0 ; + }/* + bool Lock()*/ + + bool UnLock() + { + struct sembuf sembuf_Obj; + sembuf_Obj.sem_num=0 ; // semaphore 迭 ° semaphore + sembuf_Obj.sem_op =1 ; + sembuf_Obj.sem_flg=SEM_UNDO; + + return ::semop(mh_Mutex,&sembuf_Obj, 1)==0 ; + }/* + bool UnLock()*/ + + bool Close() + { + // Ŀο semaphore ŵȴ. Լ Ŀ ipcs + // semaphore Ͽ Ÿ ʴ´. Ŀ Lock() + // ϰ ִ μ Ѳ  ̻ + // ȭ ʴ´. μ Լ ʰ ص Ŀ + // ڵ semaphore ʴ´. + + union semun SemUnion; + + const bool CB_IsOK = + (::semctl(mh_Mutex, 0, IPC_RMID, SemUnion)!=-1); + + mh_Mutex=0; return CB_IsOK; + }/* + bool Close()*/ + + public: + };/* + class ZCProcessMutex*/ + + + + /////////////////////////////////////////////// + + /////////// end class ZCProcessMutex /////////// + + /////////////////////////////////////////////// + + + + // posix mutex μ ȭ ϴ Ŭ + + + class ZCProcessMutexPosix + { + private: + + class ZCMutexData + { + protected: + friend class ZCProcessMutexPosix; + protected: + pthread_mutex_t mo_PThreadMutex ; + pthread_mutexattr_t mo_PThreadMutexAttr; + protected: + };/* + class ZCMutexData*/ + + private: + ZCMutexData* mp_MutexData ; + ZCShareMemory mo_CShareMemory; + public : + + ZCProcessMutexPosix() + { + mp_MutexData=0; + }/* + ZCProcessMutexPosix()*/ + + bool Make(LPCTSTR AP_MapName) + { + return Make( ZNsMain::ZfGetKeyNum(AP_MapName) ); + }/* + bool Make(LPCTSTR AP_MapName)*/ + + bool Make(long AL_MapKey) + { + if(mo_CShareMemory.ShmGet(AL_MapKey,sizeof(ZCMutexData))==false) + { + if(errno!=EEXIST || mo_CShareMemory.ShmGet(AL_MapKey)!=true) + { + return false; + } + if(mo_CShareMemory.LinkMap()==false) + { + mo_CShareMemory.Close(); return false; + }/* + if(mo_CShareMemory.LinkMap()==false)*/ + + mp_MutexData=(ZCMutexData*)mo_CShareMemory.GetStartAddress(); + } + else // mo_CShareMemory.ShmGet(AL_MapKey,sizeof(ZCMutexData))==true + { + if(mo_CShareMemory.LinkMap()==false) + { + mo_CShareMemory.Close(); return false; + }/* + if(mo_CShareMemory.LinkMap()==false)*/ + + mp_MutexData=(ZCMutexData*)mo_CShareMemory.GetStartAddress(); + + ::memset(mp_MutexData, 0x00, sizeof(ZCMutexData)); + + ::pthread_mutexattr_init (&mp_MutexData->mo_PThreadMutexAttr); + ::pthread_mutexattr_settype (&mp_MutexData->mo_PThreadMutexAttr, PTHREAD_MUTEX_RECURSIVE); // PTHREAD_MUTEX_ERRORCHECK ߾. 2007-05-24 20:04:00 + ::pthread_mutexattr_setpshared(&mp_MutexData->mo_PThreadMutexAttr, PTHREAD_PROCESS_SHARED); + ::pthread_mutex_init (&mp_MutexData->mo_PThreadMutex, (const pthread_mutexattr_t*)&mp_MutexData->mo_PThreadMutexAttr); + }/* + else // mo_CShareMemory.ShmGet(AL_MapKey,sizeof(ZCMutexData))==true*/ + + return true; + }/* + bool Make(long AL_MapKey)*/ + + + bool Lock() + { + return this->LockRaw()==0; + }/* + int Lock()*/ + + int LockRaw() + { + return ::pthread_mutex_lock(&mp_MutexData->mo_PThreadMutex); + + // EDEADLK ȯϴ 츦 üũ . + }/* + int Lock()*/ + + #ifdef __USE_XOPEN2K + + bool Lock(const struct timespec& AR_TimeSpec) + { + return this->LockRaw(AR_TimeSpec)==0; + }/* + int Lock(const struct timespec& AR_TimeSpec)*/ + + bool Lock(long AL_MiliSec) + { + return this->LockRaw(AL_MiliSec)==0; + }/* + int Lock(long AL_MiliSec)*/ + + int LockRaw(const struct timespec& AR_TimeSpec) + { + return ::pthread_mutex_timedlock(&mp_MutexData->mo_PThreadMutex, &AR_TimeSpec); + + // ̸ ZNsEnum::ZEThread_OK + // ðʰ̸ ZNsEnum::ZEThread_TimeOut + // + // EDEADLK ȯϴ 츦 üũ . + }/* + int Lock(const struct timespec& AR_TimeSpec)*/ + + int LockRaw(long AL_MiliSec) + { + timespec VO_TimeSpec; + + VO_TimeSpec.tv_sec =time(NULL)+AL_MiliSec/1000; + VO_TimeSpec.tv_nsec=(AL_MiliSec%1000)*1000*1000; + + return ::pthread_mutex_timedlock(&mp_MutexData->mo_PThreadMutex, &VO_TimeSpec); + }/* + int Lock(long AL_MiliSec)*/ + + int LockTime(long AL_MiliSec) + { + return LockRaw(AL_MiliSec); + }/* + int LockTime(long AL_MiliSec)*/ + + #endif // __USE_XOPEN2K + + bool UnLock() + { + return ::pthread_mutex_unlock(&mp_MutexData->mo_PThreadMutex)==0; + }/* + bool UnLock()*/ + + void Close() + { + ::pthread_mutex_destroy(&mp_MutexData->mo_PThreadMutex); + + mo_CShareMemory.UnMap(); + mo_CShareMemory.Close(); + }/* + void Close()*/ + + public: + };/* + class ZCProcessMutexPosix*/ + + +#ifdef __USE_XOPEN2K + + + /*//////////////////////////////////////////////////////////////////////////////// + + /ǵ lock(read-write lock) Window ̺Ʈ + ִ. Ư ټ 尡 ϴٰ ÿ  + . ؽ Ǻ ̺Ʈ ϴ ȿ̴. + + POSIX.1b structure for a time value. + This is like a `struct timeval' but has nanoseconds instead of microseconds. + + struct timespec + { + __time_t tv_sec ; // Seconds. + long int tv_nsec; // Nanoseconds. 10 1 , 1 и=1000*1000 + }; + + ////////////////////////////////////////////////////////////////////////////////*/ + + class ZCLockRW_Base + { + protected: + pthread_rwlock_t mo_pthread_rwlock_t; + public: + + int Init() + { + return ::pthread_rwlock_init(&mo_pthread_rwlock_t, NULL); + }/* + int Init()*/ + + int LockRead() + { + return ::pthread_rwlock_rdlock(&mo_pthread_rwlock_t); + }/* + int LockRead()*/ + + int LockRead(const struct timespec& AR_TimeSpec) + { + return ::pthread_rwlock_timedrdlock(&mo_pthread_rwlock_t, &AR_TimeSpec); + }/* + int LockRead(const struct timespec& AR_TimeSpec)*/ + + int LockRead(long AL_MiliSec) + { + timespec VO_TimeSpec; + + VO_TimeSpec.tv_sec =time(NULL)+AL_MiliSec/1000; + VO_TimeSpec.tv_nsec=(AL_MiliSec%1000)*1000*1000; + + return ::pthread_rwlock_timedrdlock(&mo_pthread_rwlock_t, &VO_TimeSpec); + }/* + int LockRead(long AL_MiliSec)*/ + + int TryLockRead() + { + return ::pthread_rwlock_tryrdlock(&mo_pthread_rwlock_t); + }/* + int TryLockRead()*/ + + int LockWrite() + { + return ::pthread_rwlock_wrlock(&mo_pthread_rwlock_t); + }/* + int LockRead()*/ + + int LockWrite(const struct timespec& AR_TimeSpec) + { + return ::pthread_rwlock_timedwrlock(&mo_pthread_rwlock_t,&AR_TimeSpec); + }/* + int LockWrite(const struct timespec& AR_TimeSpec)*/ + + int LockWrite(long AL_MiliSec) + { + timespec VO_TimeSpec; + + VO_TimeSpec.tv_sec =time(NULL)+AL_MiliSec/1000; + VO_TimeSpec.tv_nsec=(AL_MiliSec%1000)*1000*1000; + + return ::pthread_rwlock_timedwrlock(&mo_pthread_rwlock_t, &VO_TimeSpec); + }/* + int LockWrite(long AL_MiliSec)*/ + + int TryLockWrite() + { + return ::pthread_rwlock_trywrlock(&mo_pthread_rwlock_t); + }/* + int TryLockWrite()*/ + + int UnLock() + { + return ::pthread_rwlock_unlock(&mo_pthread_rwlock_t); + }/* + int UnLock()*/ + + int Close() + { + return ::pthread_rwlock_destroy(&mo_pthread_rwlock_t); + }/* + int Close()*/ + + public: + };/* + class ZCLockRW_Base*/ + + + class ZCLockRW : public ZCLockRW_Base + { + protected: + pthread_rwlockattr_t mo_pthread_rwlockattr_t; + public : + + int InitAttr() + { + return ::pthread_rwlockattr_init(&mo_pthread_rwlockattr_t); + }/* + int InitAttr()*/ + + int Init() + { + return ::pthread_rwlock_init(&mo_pthread_rwlock_t, &mo_pthread_rwlockattr_t); + }/* + int Init()*/ + + bool SetShared(int AI_PShared=PTHREAD_PROCESS_PRIVATE) + { + return ::pthread_rwlockattr_setpshared(&mo_pthread_rwlockattr_t, AI_PShared)==ZNsEnum::ZEThread_OK; + }/* + bool SetShared(int AI_PShared=PTHREAD_PROCESS_PRIVATE)*/ + + bool GetShared(int& ARRI_PShared) + { + return ::pthread_rwlockattr_getpshared(&mo_pthread_rwlockattr_t, &ARRI_PShared)==ZNsEnum::ZEThread_OK; + }/* + bool GetShared(int& ARRI_PShared)*/ + + + // ǵ, lock 켱 Լ, Posix ǥ ƴϴ. + // Լ 켱 ʾҴٸ ⺻ lock + // 켱 δ ִ . -- 2006-12-30 16:21:00 + + int GetKind(int& ARRI_Kind) const + { + return ::pthread_rwlockattr_getkind_np(&mo_pthread_rwlockattr_t, &ARRI_Kind); + }/* + int GetKind(int& ARRI_Kind) const*/ + + int SetKind(int AI_Kind=PTHREAD_RWLOCK_PREFER_READER_NP) + { + return ::pthread_rwlockattr_setkind_np(&mo_pthread_rwlockattr_t, AI_Kind); + }/* + int SetKind(int AI_Kind=PTHREAD_RWLOCK_PREFER_READER_NP)*/ + + + int CloseAttr() + { + return ::pthread_rwlockattr_destroy(&mo_pthread_rwlockattr_t); + }/* + int CloseAttr()*/ + + int Close() + { + return (ZCLockRW_Base::Close(), CloseAttr()); + }/* + int Close()*/ + + public: + };/* + class ZCLockRW*/ + + + class ZCLockRW_Process + { + protected: + ZCLockRW* mp_CLockRW ; + ZCShareMemory mo_CShareMemory; + public : + + ZCLockRW_Process() + { + mp_CLockRW=0; + }/* + ZCLockRW_Process()*/ + + bool Make(long AL_MapKey) + { + if(mo_CShareMemory.ShmGet(AL_MapKey,sizeof(ZCLockRW))==false) + { + if(errno!=EEXIST || mo_CShareMemory.ShmGet(AL_MapKey)!=true) + { + return false; + } + if(mo_CShareMemory.LinkMap()==false) + { + mo_CShareMemory.Close(); return false; + }/* + if(mo_CShareMemory.LinkMap()==false)*/ + + mp_CLockRW=(ZCLockRW*)mo_CShareMemory.GetStartAddress(); + } + else //!(mo_CShareMemory.ShmGet(AL_MapKey,sizeof(ZCLockRW))==false) + { + if(mo_CShareMemory.LinkMap()==false) + { + mo_CShareMemory.Close(); return false; + }/* + if(mo_CShareMemory.LinkMap()==false)*/ + + mp_CLockRW=(ZCLockRW*)mo_CShareMemory.GetStartAddress(); + + ::memset(mp_CLockRW,0x00,sizeof(ZCLockRW)); + + mp_CLockRW->InitAttr(); + mp_CLockRW->SetShared(PTHREAD_PROCESS_SHARED); + mp_CLockRW->Init(); + }/* + else //!(mo_CShareMemory.ShmGet(AL_MapKey,sizeof(ZCLockRW))==false)*/ + + return true; + }/* + bool Make(long AL_MapKey)*/ + + bool Make(const char* AP_KeyName) + { + int Index =-1 ; + long VL_KeyID = 10 ; + + if(AP_KeyName!=0) + { + while(AP_KeyName[++Index]!=0) + { + VL_KeyID += AP_KeyName[Index]*(Index+1) ; + }/* + while(AP_KeyName[++Index]!=0)*/ + }/* + if(AP_KeyName!=0)*/ + + return this->Make(VL_KeyID); + }/* + bool Make(const char* AP_KeyName)*/ + + int LockRead() + { + return mp_CLockRW->LockRead(); + }/* + int LockRead()*/ + + int LockRead(const struct timespec& AR_TimeSpec) + { + return mp_CLockRW->LockRead(AR_TimeSpec); + }/* + int LockRead(const struct timespec& AR_TimeSpec)*/ + + int TryLockRead() + { + return mp_CLockRW->TryLockRead(); + }/* + int TryLockRead()*/ + + int LockWrite() + { + return mp_CLockRW->LockWrite(); + }/* + int LockRead()*/ + + int LockWrite(const struct timespec& AR_TimeSpec) + { + return mp_CLockRW->LockWrite(AR_TimeSpec); + }/* + int LockWrite(const struct timespec& AR_TimeSpec)*/ + + int TryLockWrite() + { + return mp_CLockRW->TryLockWrite(); + }/* + int TryLockWrite()*/ + + int UnLock() + { + return mp_CLockRW->UnLock(); + }/* + int UnLock()*/ + + int GetKind(int& ARRI_Kind) const + { + return mp_CLockRW->GetKind(RR(ARRI_Kind)); + }/* + int GetKind(int& ARRI_Kind) const*/ + + int SetKind(int AI_Kind=PTHREAD_RWLOCK_PREFER_READER_NP) + { + return mp_CLockRW->SetKind(AI_Kind); + }/* + int SetKind(int AI_Kind=PTHREAD_RWLOCK_PREFER_READER_NP)*/ + + int Close() + { + int VI_Resutl=mp_CLockRW->Close(); + + mo_CShareMemory.UnMap(); + mo_CShareMemory.Close(); + + return VI_Resutl; + }/* + int Close()*/ + + public: + };/* + class ZCLockRW_Process*/ + + +#endif //__USE_XOPEN2K + + + /*////////////////////////////////////////////////////////////////////////////////// + + class ZCProcessSemaphore μ ȭ object. μ + ȭ Semaphore ְ, Window μ ȭ Mutex + ִ. μ ȭ ̴ Semaphore ȭ ̴ +  Լ ٸ. + + ý ȣ : semget() (SYSTEM CALL:semget()) + + ο ų ϴ տ ϱ Ͽ, semget() ý ȣ + Ѵ. + + SYSTEM CALL: semget(); + + PROTOTYPE: int semget ( key_t key, int nsems, int semflg ); + RETURNS: semaphore set IPC identifier on success + -1 on error: errno = EACCESS (permission denied) + EEXIST (set exists, cannot create (IPC_EXCL)) + EIDRM (set is marked for deletion) + ENOENT (set does not exist, no IPC_CREAT was used) + ENOMEM (Not enough memory to create new set) + ENOSPC (Maximum set limit exceeded) + NOTES: + + semget() ù° ƱԸƮ ftok() ȣ⿡ ȯ Ű̴. + Ű Ŀξȿ ϴ ٸ Ű 񱳵ȴ. ̶ ų ϴ semflg ƱԸƮ 뿡 ȴ. + + IPC_CREAT + Ŀξȿ ̹ ʴ´ٸ . + IPC_EXCL + IPC_CREAT Ǿ, ۰ ̹ ϸ Ѵ. + + IPC_CREAT ȥ ȴٸ, semget() Ȯ + (the semaphore set identifier) ȯϰų Ű ̹ ϴ + Ȯڸ ȯѴ. IPC_EXCL IPC_CREAT Բ ٸ, + ų ̹ Ѵٸ -1 ȣ⿡ Ѵ. + IPC_EXCL üδ ǹ̰ , IPC_CREAT յǾ + ʴ ۸ (access)ϱ ġ ִ. + ý V IPC ٸ µó ΰ 8 尡 㰡 ¿ ũ OR ִ. + + nsems ƱԸƮ վȿ ϴ Ѵ. + ̰ տ ߴ μ ǹѴ. + վ ִ linux/sem.h Ǿִ. + + #define SEMMSL 32 // <=512 id ִ + + ̹ ϴ Ȯ ִٸ, nsems ƱԸƮ õʿ ָض. + wrapper Լ : + + int open_semaphore_set( key_t keyval, int numsems ) + { + int sid; + + if ( ! numsems ) + return(-1); + if((sid = semget( mykey, numsems, IPC_CREAT | 0660 )) == -1) + return(-1); + //endif + + return(sid); + } + //int open_semaphore_set( key_t keyval, int numsems ) + + 0600 㰡 Կ ض. + Լ Ȯ(int) ȯϰų -1 ȯѴ. + ٸ, Ҵϱ Ű Ѱ Ѵ. + ǥ , ϴ ʴ + ϱ IPC_EXCL ÷ 뿡 ָض + + -- NOTES -- + + int semctl ( int semid, int semnum, int cmd, union semun arg ); + + -1 on error: errno = EACCESS (permission denied) + EFAULT(invalid address pointed to by arg argument) + EIDRM (semaphore set was removed) + EINVAL(set doesn't exist, or semid is invalid) + EPERM (EUID has no privileges for cmd in arg) + ERANGE(semaphore value out of range) + + semctl() Լ 3 ° μ ִ + + IPC_STAT + տ semid_ds ȸϰ, + semun union buf ƱԸƮ ּ Ѵ. + + IPC_SET + տ semid_ds ipc_perm Ѵ. + semum union buf ƱԸƮ ´. + + IPC_RMID + Ŀη Ѵ. + + GETALL + µ ȴ. + union 迭 unsigned short integer 迭 ȴ. + + GETCNT + ڿ ٸ ִ μ ȯѴ. + + GETPID + semop ȣ μ PID ȯѴ. + + GETZCNT + 100% ڿ Ȱ ٸ ִ μ ȯѴ. + + SETALL + վ union 迭 ȿ Ե ĪǴ Ѵ. + + SETVAL + վ union val Ѵ. + + arg ƱԸƮ semun Ÿ Ÿ. + Ư ü(union) linux/sem.h Ǿִ. + + union semun + { + int val; // SETVAL + struct semid_ds *buf; // IPC_STAT & IPC_SET + ushort *array; // GETALL & SETALL 迭 + struct seminfo *__buf; // IPC_INFO + void *__pad; + }; + + val + SETVAL ɾ ȴ.ۿ Ѵ. + + buf + IPC_STAT/IPC_SET ȴ. + Ŀξȿ Ǵ ڷ 纻 Ÿ. + + array + GETALL/SETALL ɾ Ǵ . + վȿ ȸϰų ϴµ Ǵ + 迭 Ű ־ Ѵ. + ִ ƱԸƮ _buf _pad Ŀ ڵ峻 + Ǹ α׷ ڿԴ . + ǻ, ̷ ΰ ƱԸƮ ü Ǹ + ٸ н ã . + ̷ Ư ý ȣ ý V IPC ȣ ϴµ + Ƿ, ̷ پ ˻ ̴. + + ƱԸƮ(union) GETVAL ɾ õȴ. + + Posix Semaphore unistd.h Ͽ _POSIX_SEMAPHORES ɼ + ǵǾ ִ. + + -- POSIX() 带 ̿ α׷ (2011-05-23 20:31:00) + + //////////////////////////////////////////////////////////////////////////////////*/ + + + class ZCProcessSemaphore + { + private: + ZTypeID mh_Semaphore; + public : + + ZCProcessSemaphore() + { + mh_Semaphore=0; + }/* + ZCProcessSemaphore()*/ + + // Linux  迭 + // ϳ 迭 Ѵ. + + bool Make(const char* AP_SemaName, long AL_InitialCnt, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) + { + return this->Make(ZNsMain::ZfGetKeyNum(AP_SemaName), AL_InitialCnt, AI_Flag); + }/* + bool Make(const char* AP_SemaName, long AL_InitialCnt, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664)*/ + + bool Make(long AL_KeyID,int AL_InitialCnt,int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) + { + if((mh_Semaphore=semget((key_t)AL_KeyID,1,AI_Flag))==-1) + { + if(errno==EEXIST) + return (mh_Semaphore=semget((key_t)AL_KeyID,1,0))!=-1 ; + return false; + }/* + if((mh_Semaphore=semget((key_t)AL_KeyID,1,AI_Flag))==-1)*/ + + union semun SemUnion; SemUnion.val=AL_InitialCnt; + + return semctl(mh_Semaphore, 0, SETVAL,SemUnion) != -1 ; + }/* + bool Make(long AL_KeyID,int AL_InitialCnt,int AI_Flag=IPC_CREAT | IPC_EXCL | 0664)*/ + + + // Ʒ Լ ؽó ϴµ . + + bool Make(int AL_InitialCnt=1, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) + { + return Make(this->GetUniqueSemaKey(), AL_InitialCnt, AI_Flag); + }/* + bool Make(int AL_InitialCnt=1, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664)*/ + + + // ȣ  . + + bool MakeZero(int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) + { + return Make(this->GetUniqueSemaKey(), 0, AI_Flag); + }/* + bool MakeZero(int AI_Flag=IPC_CREAT | IPC_EXCL | 0664)*/ + + + static long GetUniqueSemaKey() + { + static long SL_UniqueID=0 ; + const long CL_AddID =100000; + + return ( SL_UniqueID += CL_AddID ) + ::getpid() ; + }/* + static long GetUniqueSemaKey()*/ + + + bool MakeArr(long AL_KeyID, int AL_InitialCnt, int AI_SemaCnt, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) + { + if((mh_Semaphore=semget((key_t)AL_KeyID, AI_SemaCnt, AI_Flag))==-1) + { + if(errno==EEXIST) + return (mh_Semaphore=semget((key_t)AL_KeyID, AI_SemaCnt,0))!=-1 ; + + return false; + }/* + if((mh_Semaphore=semget((key_t)AL_KeyID, AI_SemaCnt, AI_Flag))==-1)*/ + + union semun SemUnion; SemUnion.val=AL_InitialCnt; + + // ʱȭ SETALL ɼ ص Ǵµ SemUnion.array 迭 Ҵϰ + // ʱȭϰ ϴ ϸ ׳ for ε . + + __for0(ZTypInt, i, AI_SemaCnt) + { + if(semctl(mh_Semaphore, i, SETVAL,SemUnion) != -1 ) return false; + }/* + __for0(ZTypInt, i, AI_SemaCnt)*/ + + return true; + }/* + bool MakeArr(long AL_KeyID, int AL_InitialCnt, int AI_SemaCnt, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664)*/ + + bool MakeArr(const char* AP_SemaName, int AL_InitialCnt, int AI_SemaCnt, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) + { + return MakeArr(ZNsMain::ZfGetKeyNum(AP_SemaName), AL_InitialCnt, AI_SemaCnt, AI_Flag); + }/* + bool MakeArr(const char* AP_SemaName, int AL_InitialCnt, int AI_SemaCnt, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664)*/ + + + // bool MakeStd() class ZCProcessSemaphore Window, Linux ʿ ȣȯϱ , + // μ AI_MaxSemaCnt ʰ ִ.(Window ǹ̰ ִ.) + + bool MakeStd(const char* AP_SemaName, int AL_InitialCnt, int AI_MaxSemaCnt, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) + { + return this->Make(ZNsMain::ZfGetKeyNum(AP_SemaName), AL_InitialCnt, AI_Flag); + }/* + bool MakeStd(const char* AP_SemaName, int AL_InitialCnt, int AI_MaxSemaCnt, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664)*/ + + bool Open(const char* AP_SemaName) + { + return (mh_Semaphore=semget((key_t)(ZNsMain::ZfGetKeyNum(AP_SemaName)), 1, 0))>0 ; + }/* + bool Open(const char* AP_SemaName)*/ + + + // ´. + + int GetValue(int AI_SemaNum=0) + { + return semctl(mh_Semaphore, AI_SemaNum, GETVAL, 0/*union semun arg*/) ; + }/* + int GetValue(int AI_SemaNum=0)*/ + + bool GetValue(union semun& ARR_SemUnion) + { + return semctl(mh_Semaphore, 0/*ignored*/, GETALL, ARR_SemUnion) !=-1 ; + }/* + bool GetValue(union semun& ARR_SemUnion)*/ + + bool IsZeroCount() + { + return this->GetValue()==0; + }/* + bool IsZeroCount()*/ + + bool Lock(ZTypUInt AI_ReleaseCount=1) + { + return LockRaw(AI_ReleaseCount)!=-1; + }/* + bool Lock(ZTypUInt AI_ReleaseCount=1)*/ + + + // LockRaw() ̸ ZEThread_OK, ð ʰ ZEThread_TimeOut ȯѴ. + // Posix  . + + int LockRaw(ZTypUInt AI_ReleaseCount=1) + { + // cf) Window ReleaseSemaphore(mh_Semaphore,lReleaseCount,lpPreviousCount) + // ι° μ AI_ReleaseCount Ѵ. + + struct sembuf sem_b; + + sem_b.sem_num= 0 ; + sem_b.sem_op =-AI_ReleaseCount; + sem_b.sem_flg= SEM_UNDO ; + + return semop(mh_Semaphore, &sem_b,1) ; + }/* + int LockRaw(ZTypUInt AI_ReleaseCount=1)*/ + + bool UnLock(ZTypUInt AI_ReleaseCount=1) + { + // cf) Window ReleaseSemaphore(mh_Semaphore,lReleaseCount,lpPreviousCount) + // ι° μ AI_ReleaseCount Ѵ. + + struct sembuf sem_b; + + sem_b.sem_num=0; + sem_b.sem_op =AI_ReleaseCount; + sem_b.sem_flg=SEM_UNDO; + + return semop(mh_Semaphore, &sem_b,1)!=-1 ; + }/* + bool UnLock(ZTypUInt AI_ReleaseCount=1)*/ + + bool Close() + { + union semun SemUnion; bool VB_IsOK = + (semctl(mh_Semaphore, 0, IPC_RMID ,SemUnion)!=-1) ; + + mh_Semaphore=0; return VB_IsOK; + }/* + bool Close()*/ + + public: + };/* + class ZCProcessSemaphore*/ + + + + /////////////////////////////////////////////// + + /////////// end class ZCProcessMutex /////////// + + /////////////////////////////////////////////// + + + /*///////////////////////////////////////////// + + #define SEM_FAILED 0 + #define SEM_VALUE_MAX 1147483648 + + int sem_init (sem_t * sem, int pshared, unsigned int value); + int sem_destroy (sem_t * sem); + sem_t *sem_open (const char *name, int oflag, ...); + int sem_close (sem_t *sem); + int sem_wait (sem_t * sem); + int sem_trywait (sem_t * sem); + int sem_timedwait (sem_t * sem, const struct timespec *abstime); + int sem_post (sem_t * sem); + int sem_getvalue(sem_t * sem, int *sval); + + + cf) + + #include + + int sem_wait(sem_t *sem); + int sem_trywait(sem_t *sem); + + DESCRIPTION + The sem_wait() function locks the semaphore referenced by sem + by performing a semaphore lock operation on that semaphore. + If the semaphore value is currently zero, + then the calling thread will not return from the call to sem_wait() + until it either locks the semaphore or the call is interrupted by a signal. + The sem_trywait() function locks the semaphore referenced by sem + only if the semaphore is currently not locked; + that is, if the semaphore value is currently positive. + Otherwise, it does not lock the semaphore. + Upon successful return, + the state of the semaphore is locked and remains locked + until the sem_post() function is executed and returns successfully. + + The sem_wait() function is interruptible by the delivery of a signal. + + + + HMUG - Mac OS X / Darwin man pages + Current Directory /man/2 + + -------------------------------------------------------------------------------- + + NAME + + sem_open - initialize and open a named semaphore + + SYNOPSIS + + #include + + sem_t* sem_open(const char *name, int flags) + sem_t* sem_open(const char *name, int flags, mode_t mode, unsigned int value) + + DESCRIPTION + The named semaphore named name is initialized and opened as specified by + the argument flags and a semaphore descriptor is returned to the calling + process. + + The flags specified are formed by or'ing the following values: + + O_CREAT create the semaphore if it does not exist + O_EXCL error if create and semaphore exists + + If O_CREATE if specified, sem_open() requires an additional two argu- + ments. mode specifies the permissions for the semaphore as described in + chmod(2) and modified by the process' umask value (see umask(2)). The + semaphore is created with an initial value, which must be less than or + equal to SEM_VALUE_MAX. + + If O_EXCL is specified and the semaphore exists, sem_open() fails. The + check for the existence of the semaphore and the creation of the + semaphore are atomic with respect to all processes calling sem_open() + with O_CREAT and O_EXCL set. + + When a new semaphore is created, it is given the user ID and group ID + which coorespond to the effective user and group IDs of the calling pro- + cess. There is no visible entry in the file system for the created object + in this implementation. + + The returned semaphore descriptor is available to the calling process un- + til it is closed with sem_close(), or until the caller exits or execs. + + If a process makes repeated calls to sem_open(), with the same name argu- + ment, the same descriptor is returned for each successful call, unless + sem_unlink() has been called on the semaphore in the interim. + + If sem_open() fails for any reason, it will return a value of SEM_FAILED + and sets errno. On success, it returns a semaphore descriptor. + + + ERRORS + + The named semaphore is opened unless: + + [EACCES] The required permissions (for reading and/or writing) are + denied for the given flags; or O_CREAT is specified, the + object does not exist, and permission to create the + semaphore is denied. + + [EEXIST] O_CREAT and O_EXCL were specified and the semaphore exists. + + [EINTR] The sem_open() operation was interrupted by a signal. + + [EINVAL] The shm_open() operation is not supported; or O_CREAT is + specified and value exceeds SEM_VALUE_MAX. + + [EMFILE] The process has already reached its limit for semaphores or + file descriptors in use. + + [ENAMETOOLONG] + name exceeded SEM_NAME_LEN characters. + + [ENFILE] Too many semaphores or file descriptors are open on the + system. + + [ENOENT] O_CREAT is not set and the named semaphore does not exist. + + [ENOSPC] O_CREAT is specified, the file does not exist, and there is + insufficient space available to create the semaphore. + + SEE ALSO + semctl(2), semget(2), semop(2), sem_close(2), sem_post(2), + sem_trywait(2), sem_unlink(2), sem_wait(2), umask(2) + + HISTORY + sem_open() is specified in the POSIX Realtime Extension + (1003.1b-1993/1003.1i-1995). + + Darwin Operating System June 8, 2000 2 + + /////////////////////////////////////////////*/ + + + /*////////////////////////////////////////////////////////// + + class ZCThreadSemaphore ȣȯDZ ƴ. + ȣȯ class ZCProcessSemaphore ణ . + + sem_t 0 . + + //////////////////////////////////////////////////////////*/ + + class ZCThreadSemaphore + { + private: + sem_t mh_Semaphore; + public : + + /*///////////////////////////////////////////////////////////////////////////// + + sem_init() Լ ̸  鶧 Ѵ. ̸ִ + sem_open() ؾ ϸ, ı sem_close() sem_unlink() + ؾ Ѵ. Ŭ ̸  ٷ. + + AI_Shared 0 ƴϸ μ Linux + sem_XXX 迭 Լ ʰ ִ.(2004.7.12) + + AI_InitValue==1 ̶ ؽó Ϸ ̴. 2007-09-30 14:32:00 + + /////////////////////////////////////////////////////////////////////////////*/ + + bool Make(int AI_InitValue=1,int AI_Shared=0) + { + return ::sem_init(&mh_Semaphore, AI_Shared, AI_InitValue) !=-1 ; + }/* + bool Make(int AI_InitValue=1,int AI_Shared=0);*/ + + bool MakeZero(int AI_Shared=0) + { + return ::sem_init(&mh_Semaphore,AI_Shared,0) !=-1 ; + }/* + bool MakeZero(int AI_Shared=0)*/ + + bool Lock() + { + return ::sem_wait(&mh_Semaphore)==0 ; + }/* + bool Lock()*/ + + int LockRaw() + { + return ::sem_wait(&mh_Semaphore); + }/* + int LockRaw()*/ + + #ifdef __USE_XOPEN2K + + // cf) int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); + + int LockRaw(const struct timespec& AR_TimeOut) + { + // timeout ̸ errno ZNsEnum::ZEThread_TimeOut + + if(::sem_timedwait(&mh_Semaphore, &AR_TimeOut)!=ZNsEnum::ZEThread_OK) + return errno; + //endif + + return ZNsEnum::ZEThread_OK; + }/* + int Lock(const struct timespec& AR_TimeOut)*/ + + int LockRaw(long AL_MiliSec) + { + timespec VO_TimeSpec; + + VO_TimeSpec.tv_sec =time(NULL)+AL_MiliSec/1000; + VO_TimeSpec.tv_nsec=(AL_MiliSec%1000)*1000*1000; + + return ::sem_timedwait(&mh_Semaphore,&VO_TimeSpec); + }/* + LockRaw LockRaw(long AL_MiliSec)*/ + + int LockTime(long AL_MiliSec) + { + return LockRaw(AL_MiliSec); + }/* + int LockTime(long AL_MiliSec)*/ + + #endif //__USE_XOPEN2K + + // sem_trywait() ̹ lock ɷ -1 + // ȯϰ, errno EAGAIN õȴ. + + bool TryLock() + { + return ::sem_trywait(&mh_Semaphore)==0 ; + }/* + bool TryLock()*/ + + bool UnLock() + { + return ::sem_post(&mh_Semaphore)==0 ; + }/* + bool UnLock()*/ + + + // sem_destroy() Լ ̸ ſ Ǵ Լ. + // ̸ִ  쿡 ǵǾ ʴ. + + bool Close() + { + return (sem_destroy(&mh_Semaphore)==0); + }/* + bool Close()*/ + + int GetValue() const + { + int VI_Val=0; const bool CB_IsOK = + (::sem_getvalue((sem_t*)&mh_Semaphore, &VI_Val)!=0); + + if(CB_IsOK) return -1; return VI_Val; + }/* + int GetValue() const*/ + + public: + };/* + class ZCThreadSemaphore*/ + + + + // ؽ ؼ . + + class ZCThreadMutex + { + private : + + ZCThreadMutex(const ZCThreadMutex& rhs){} + + ZCThreadMutex& operator=(const ZCThreadMutex& rhs) + { + return *this; + }/* + ZCThreadMutex& operator=(const ZCThreadMutex& rhs)*/ + + /*private :*/ + protected: + pthread_mutex_t mo_Mutex; + public : + + ZCThreadMutex() + { + }/* + ZCThreadMutex()*/ + + const pthread_mutex_t& GetMutexID() const + { + return mo_Mutex; + }/* + const pthread_mutex_t& GetMutexID() const*/ + + pthread_mutex_t& GetMutexID() + { + return mo_Mutex; + }/* + pthread_mutex_t& GetMutexID()*/ + + bool Make(const pthread_mutexattr_t* AP_MutexAttr=0) + { + return pthread_mutex_init(&mo_Mutex, AP_MutexAttr)==0 ; + }/* + bool Make(const pthread_mutexattr_t* AP_MutexAttr=0)*/ + + bool Lock() + { + return this->LockRaw()==0 ; + }/* + bool Lock()*/ + + int LockRaw() + { + return pthread_mutex_lock(&mo_Mutex) ; + }/* + int LockRaw()*/ + + #ifdef __USE_XOPEN2K + + bool Lock(long AL_MiliSec) + { + return this->LockRaw(AL_MiliSec)==0 ; + }/* + bool Lock(long AL_MiliSec)*/ + + + // cf) 30 ʰ LOCK + // + // struct timespec ts_timeout; + // ts_timeout.tv_sec =time(NULL)+30; + // ts_timeout.tv_nsec=0; + + int LockRaw(const struct timespec& AR_TimeOut) + { + return pthread_mutex_timedlock(&mo_Mutex, &AR_TimeOut) ; + }/* + int LockRaw(const struct timespec& AR_TimeOut)*/ + + int LockRaw(long AL_MiliSec) + { + timespec VO_TimeSpec; + + VO_TimeSpec.tv_sec = time(NULL)+AL_MiliSec/1000 ; + VO_TimeSpec.tv_nsec= (AL_MiliSec%1000)*1000*1000 ; + + return pthread_mutex_timedlock(&mo_Mutex, &VO_TimeSpec) ; + }/* + int LockRaw(long AL_MiliSec)*/ + + int LockTime(long AL_MiliSec) + { + return LockRaw(AL_MiliSec); + }/* + int LockTime(long AL_MiliSec)*/ + + #endif //__USE_XOPEN2K + + int TryLock() + { + return pthread_mutex_trylock(&mo_Mutex); + }/* + int TryLock()*/ + + bool UnLock() + { + return pthread_mutex_unlock(&mo_Mutex)==0 ; + }/* + bool UnLock()*/ + + bool Close() + { + return pthread_mutex_destroy(&mo_Mutex)==0 ; + }/* + bool Close()*/ + + public: + };/* + class ZCThreadMutex*/ + + + class ZCThreadMutexAttr + { + private: + + ZCThreadMutexAttr(const ZCThreadMutexAttr& rhs) + { + }/* + ZCThreadMutexAttr(const ZCThreadMutexAttr& rhs)*/ + + ZCThreadMutexAttr& operator=(const ZCThreadMutexAttr& rhs) + { + return *this; + }/* + ZCThreadMutexAttr& operator=(const ZCThreadMutexAttr& rhs)*/ + + /*private :*/ + protected: + + pthread_mutex_t mo_Mutex ; + pthread_mutexattr_t mo_PThreadMutexAttr; + + public : + + ZCThreadMutexAttr() + { + }/* + ZCThreadMutexAttr()*/ + + const pthread_mutex_t& GetMutexID() const + { + return mo_Mutex; + }/* + const pthread_mutex_t& GetMutexID() const*/ + + pthread_mutex_t& GetMutexID() + { + return mo_Mutex; + }/* + pthread_mutex_t& GetMutexID()*/ + + bool Make(int AI_ThreadType=PTHREAD_MUTEX_RECURSIVE) + { + // PTHREAD_MUTEX_RECURSIVE mutex 忡 ŭ ؾѴ. + // Ŭ ڿ ϰ Ҹڿ ϱ⿡ . + + if(pthread_mutexattr_init(&mo_PThreadMutexAttr)!=0) + return false; + if(pthread_mutexattr_settype(&mo_PThreadMutexAttr,AI_ThreadType)!=0) + return false; + if(pthread_mutexattr_setpshared(&mo_PThreadMutexAttr,PTHREAD_PROCESS_SHARED)!=0) + return false; + //endif + + /*/////////////////////////////////////////////////////////////////////////////// + + if(pthread_mutexattr_setpshared(&mo_PThreadMutexAttr,PTHREAD_PROCESS_PRIVATE)!=0) + return false; + //endif + + ѵ, Mutex μ ̿ ǰ ϰ ʹٸ PTHREAD_PROCESS_SHARED + ⺻ ϴ ´. + + -- 2010-01-04 11:59:00 + + ///////////////////////////////////////////////////////////////////////////////*/ + + return pthread_mutex_init(&mo_Mutex,(const pthread_mutexattr_t*)&mo_PThreadMutexAttr)==0 ; + }/* + bool Make(int AI_ThreadType=PTHREAD_MUTEX_RECURSIVE)*/ + + bool Make(const pthread_mutexattr_t* AP_MutexAttr) + { + return pthread_mutex_init(&mo_Mutex, AP_MutexAttr)==0 ; + }/* + bool Make(const pthread_mutexattr_t* AP_MutexAttr)*/ + + bool Lock() + { + return this->LockRaw()==0 ; + }/* + bool Lock()*/ + + #ifdef __USE_XOPEN2K + + bool Lock(long AL_MiliSec) + { + return this->LockRaw(AL_MiliSec)==0 ; + }/* + bool Lock(long AL_MiliSec)*/ + + #endif //__USE_XOPEN2K + + int LockRaw() + { + return pthread_mutex_lock(&mo_Mutex) ; + }/* + int LockRaw()*/ + + + // cf) 30 ʰ LOCK + // + // struct timespec ts_timeout; + // ts_timeout.tv_sec=time(NULL)+30; + // ts_timeout.tv_nsec=0; + + #ifdef __USE_XOPEN2K + + int LockRaw(const struct timespec& AR_TimeOut) + { + return pthread_mutex_timedlock(&mo_Mutex, &AR_TimeOut) ; + }/* + int LockRaw(const struct timespec& AR_TimeOut)*/ + + int LockRaw(long AL_MiliSec) + { + timespec VO_TimeSpec; + + VO_TimeSpec.tv_sec = time(NULL)+AL_MiliSec/1000 ; + VO_TimeSpec.tv_nsec= (AL_MiliSec%1000)*1000*1000 ; + + return pthread_mutex_timedlock(&mo_Mutex, &VO_TimeSpec) ; + }/* + int LockRaw(long AL_MiliSec)*/ + + #endif //__USE_XOPEN2K + + int TryLock() + { + return pthread_mutex_trylock(&mo_Mutex); + }/* + int TryLock()*/ + + bool UnLock() + { + return pthread_mutex_unlock(&mo_Mutex)==0 ; + }/* + bool UnLock()*/ + + bool Close() + { + return pthread_mutexattr_destroy(&mo_PThreadMutexAttr)==0 && + pthread_mutex_destroy (&mo_Mutex) ==0 ; + /////// + }/* + bool Close()*/ + + public: + };/* + class ZCThreadMutexAttr*/ + + + typedef ZCThreadMutexAttr ZCThreadMutexStd; + + + class ZCThreadMutexEasy : protected ZCThreadMutex + { + public: + + ZCThreadMutexEasy() + { + if(this->ZCThreadMutex::Make()==false) + { + std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); + fileout<ZCThreadMutex::Make()==false)*/ + }/* + ZCThreadMutexEasy()*/ + + + /*/////////////////////////////////////////////////////////////////////////////////////////////////////////// + + Ʒ + + ZCThreadMutexEasy(const ZCThreadMutexEasy& rhs) : ZCThreadMutex() + + ZCThreadMutex() g++ 4.4.6 -W ɼ ָ, Ʒ ޽ ִ. + + warning: base class 'class std::ZCThreadMutex' should be explicitly initialized in the copy constructor + + ޽ ո̶ Ǵ , Ϸ Ŭ ZCThreadMutex(rhs) ȣ + ̶ ߱ ̴. + + -- 2013-05-05 06:49:00 + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////*/ + + ZCThreadMutexEasy(const ZCThreadMutexEasy& rhs) : ZCThreadMutex() + { + if(this->ZCThreadMutex::Make()==false) + { + std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); + fileout<ZCThreadMutex::Make()==false)*/ + }/* + ZCThreadMutexEasy(const ZCThreadMutexEasy& rhs)*/ + + ~ZCThreadMutexEasy() + { + if(this->ZCThreadMutex::Close()==false) + { + std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); + fileout<ZCThreadMutex::Close()==false)*/ + }/* + ~ZCThreadMutexEasy()*/ + + + using ZCThreadMutex::Lock ; + using ZCThreadMutex::UnLock; + + public: + };/* + class ZCThreadMutexEasy*/ + + + class ZCThreadMutexAttrEasy : protected ZCThreadMutexAttr + { + public: + + ZCThreadMutexAttrEasy() + { + if(this->ZCThreadMutexAttr::Make()==false) + { + std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); + fileout<ZCThreadMutexAttr::Make()==false)*/ + }/* + ZCThreadMutexAttrEasy()*/ + + + /*/////////////////////////////////////////////////////////////////////////////////////////////////////////// + + Ʒ + + ZCThreadMutexAttrEasy(const ZCThreadMutexAttrEasy&) : ZCThreadMutexAttr() + + ZCThreadMutex() g++ 4.4.6 -W ɼ ָ, Ʒ ޽ ִ. + + warning: base class 'class std::ZCThreadMutexAttr' should be explicitly initialized in the copy constructor + + ޽ ո̶ Ǵ , Ϸ Ŭ ZCThreadMutexAttr(rhs) + ȣ ̶ ߱ ̴. + + -- 2013-05-05 06:49:00 + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////*/ + + ZCThreadMutexAttrEasy(const ZCThreadMutexAttrEasy&) : ZCThreadMutexAttr() + { + if(this->ZCThreadMutexAttr::Make()==false) + { + std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); + fileout<ZCThreadMutexAttr::Make()==false)*/ + }/* + ZCThreadMutexAttrEasy(const ZCThreadMutexAttrEasy&)*/ + + ~ZCThreadMutexAttrEasy() + { + if(this->ZCThreadMutexAttr::Close()==false) + { + std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); + fileout<ZCThreadMutexAttr::Close()==false)*/ + }/* + ~ZCThreadMutexAttrEasy()*/ + + + using ZCThreadMutexAttr::Lock ; + using ZCThreadMutexAttr::UnLock; + + public: + };/* + class ZCThreadMutexAttrEasy*/ + + + /*///////////////////////////////////////////////////////// + + Ʒ ⺻ ؽ ZCThreadMutexEasy + (׽Ʈ dead lock ߻Ѵ) ټ + ϴ.(Window Mutex ؼ) + + typedef ZCThreadMutexEasy ZCDefLockEasy; + + ׷ Ʒ ٲ۴. -- 2009-07-28 16:27:00 + + Mutex ϴ Ȳ ƾ Ѵ. + + -- 2013-07-22 12:28:00 + + freebsd 8.2 ׽Ʈ , ڲ + + pthread_mutexattr_setpshared( + &mo_PThreadMutexAttr,PTHREAD_PROCESS_SHARED + )!=0 + + Ǵ ־, ZCThreadMutexEasy + . ׷ __MUTEX_EASY_DEFAULT_LOCK__ ǵǾ + , + + typedef ZCThreadMutexEasy ZCDefLockEasy; + + ϰ Ѵ. -- 2011-05-19 22:00:00 + + ⺻ ZCThreadMutexEasy ϰ ZCThreadMutexAttrEasy + __MUTEX_ATTR_EASY_DEFAULT_LOCK__ ǵǾ , + ϴ Ѵ. -- 2015-09-02 21:05:00 + + /////////////////////////////////////////////////////////*/ + +#ifdef __MUTEX_ATTR_EASY_DEFAULT_LOCK__ + typedef ZCThreadMutexAttrEasy ZCDefLockEasy; +#else + typedef ZCThreadMutexEasy ZCDefLockEasy; +#endif + + +#ifdef __USE_XOPEN2K + + /*/////////////////////////////////////////////////////////////////////// + + spin lock ª ð ȭ . ׷ Ϲ ȭ + ؽ . spin lock context switching δ Ǿ + ĩ ӵ ִ. ʾ ɷ ϴ + ߻Ѵ. + + ؽ ƴ spin lock ȭ ϴ 쿡 ȭ + ª ð Ѵ. ȭ ֿܼ ϴ ' + ó' ڴ. Ƽ 忡 spin lock ȭ + , ټ ' ó' , ۾ 尡 ؽƮ Ī + ϸ鼭 ȭ ְ ٸ ۾ + ȭ cpu spin ϰ ִٸ ȭ ʾ, + dead lock ִ. + + -- 2008-03-20 11:27:00 + + ///////////////////////////////////////////////////////////////////////*/ + + class ZCSpinLock + { + private: + pthread_spinlock_t mh_SpinLock; + public : + + int Init(int AI_ShareMode=PTHREAD_PROCESS_PRIVATE) + { + // μ spin lock Ѵٸ PTHREAD_PROCESS_SHARED ش. + // ׸ pthread_spinlock_t ޸𸮿 ־ Ѵ. ϴ. + + return pthread_spin_init(&mh_SpinLock,AI_ShareMode); + }/* + void Init(int AI_ShareMode=PTHREAD_PROCESS_PRIVATE)*/ + + int Close() + { + return pthread_spin_destroy(&mh_SpinLock); + }/* + void Close()*/ + + int Delete() // for windows compatability + { + return this->Close(); + }/* + void Delete()*/ + + int Lock() + { + return pthread_spin_lock(&mh_SpinLock); + }/* + void Lock()*/ + + int TryLock() + { + return pthread_spin_trylock(&mh_SpinLock); + }/* + void TryLock()*/ + + int UnLock() + { + return pthread_spin_unlock(&mh_SpinLock); + }/* + void UnLock()*/ + + public: + };/* + class ZCSpinLock*/ + + + class ZCSpinLockEasy : protected ZCSpinLock + { + public: + /*####################################################################### + + Ҹڸ Լ throw(ZtCExceptBase) + ٿµ, g++ 7.3.0 . + + CProcess_Linux.H:2429:25: warning: + dynamic exception specifications are deprecated in C++11 [-Wdeprecated] + ZCSpinLockEasy() throw(ZtCExceptBase) + + -- 2018-06-26 15:12:00 + + #######################################################################*/ + + ZCSpinLockEasy() /*throw(ZtCExceptBase)*/ + { + int VI_Return=this->Init(); + + if(VI_Return!=0) + { + throw ZtCExceptBase(VI_Return); + }/* + if(VI_Return!=0)*/ + }/* + ZCSpinLockEasy()*/ + + ZCSpinLockEasy(const ZCSpinLockEasy& rhs) + { + int VI_Return=this->Init(); + + if(VI_Return!=0) + { + throw ZtCExceptBase(VI_Return); + }/* + if(VI_Return!=0)*/ + }/* + ZCSpinLockEasy(const ZCSpinLockEasy& rhs)*/ + + void Lock() + { + int VI_Return=this->ZCSpinLock::Lock(); + + if(VI_Return!=0) + { + throw ZtCExceptBase(VI_Return); + }/* + if(VI_Return!=0)*/ + }/* + void Lock() throw(ZtCExceptBase)*/ + + void UnLock() + { + int VI_Return=this->ZCSpinLock::UnLock(); + + if(VI_Return!=0) + { + throw ZtCExceptBase(VI_Return); + }/* + if(VI_Return!=0)*/ + }/* + void UnLock() throw(ZtCExceptBase)*/ + + ~ZCSpinLockEasy() + { + this->Delete(); + }/* + ZCSpinLockEasy()*/ + + public: + };/* + class ZCSpinLockEasy : protected ZCSpinLock*/ + + + typedef ZCSpinLock ZCCriticSect ; + typedef ZCSpinLockEasy ZCCriticSectEasy; + +#else // !__USE_XOPEN2K + + typedef ZCThreadMutex ZCCriticSect ; + typedef ZCThreadMutexEasy ZCCriticSectEasy; + +#endif //!__USE_XOPEN2K + + + template class ZtCAutoKeyRev; + + + /*//////////////////////////////////////////////// + + class ZtCAutoKey<> : Lock ϰ Ѵ. + + ִ Key Ͽ. + + -- + + ̷ RAII + + Resource Acquisition Is Initialization + + Ѵٴ ˾Ҵ. -- 2015-03-10 15:08:00 + + ////////////////////////////////////////////////*/ + + template< typename TCriticSectEasy=ZCThreadMutexEasy + > + class ZtCAutoKey ///////////////////////////////////// + { + public : + template friend class ZtCAutoKeyRev; + private: + ZtCAutoKey(const ZtCAutoKey&){} + private: + + TCriticSectEasy& mr_SyncEasy; + + #ifdef _DEBUG_CAUTOKEY_ + static int msi_CallCnt; + #endif //_DEBUG_CAUTOKEY_ + + public: + + ZtCAutoKey(TCriticSectEasy& AR_SyncEasy):mr_SyncEasy(AR_SyncEasy) + { + #ifdef _DEBUG_CAUTOKEY_ + cout<<" ZtCAutoKey:: ZtCAutoKey() "< class ZtCAutoKey */ + + #ifdef _DEBUG_CAUTOKEY_ + + template + int ZtCAutoKey::msi_CallCnt = 0 ; + + #endif //_DEBUG_CAUTOKEY_ + + + /*//////////////////////////////////////////////////////////////// + + ZtCAutoKeyRev<> ZtCAutoKey<> ڿ μ ޾Ƽ + ڿ Lock ϰ, Ҹڿ ٽ Lock ɾ ش. + ׷ ̷ ؾ Ȳ ü . ϴ + Dead Lock ¿ . + + 2008-04-09 21:01:00 + + ////////////////////////////////////////////////////////////////*/ + + template class ZtCAutoKeyRev + { + private: + TAutoKey& mr_CAutoKey; + public : + + ZtCAutoKeyRev(TAutoKey& AR_CAutoKey):mr_CAutoKey(AR_CAutoKey) + { + mr_CAutoKey.mr_SyncEasy.UnLock(); + }/* + ZtCAutoKeyRev(TAutoKey& AR_CAutoKey)*/ + + ~ZtCAutoKeyRev() + { + mr_CAutoKey.mr_SyncEasy.Lock(); + }/* + ~ZtCAutoKeyRev()*/ + + public: + };/* + template class ZtCAutoKeyRev */ + + +#ifdef __USE_XOPEN2K + + class ZCSpinLockProcess + { + public : + enum{EReturn_ShareMemNone = -2}; // ش ޸ + enum{EReturn_ShareMemMapErr= -3}; // ޸ Map + private: + + pthread_spinlock_t* mph_SpinLock ; + ZCShareMemory mo_CShareMemory; + + public : + + int Init(long AL_MemMapkey) + { + if(mo_CShareMemory.ShmGet(AL_MemMapkey, sizeof(pthread_spinlock_t))==false) + { + if(errno!=EEXIST || mo_CShareMemory.ShmGet(AL_MemMapkey)!=true) + { + return this->EReturn_ShareMemNone; + }/* + if(errno!=EEXIST || mo_CShareMemory.ShmGet(AL_MemMapkey)!=true)*/ + + if(this->mo_CShareMemory.LinkMap()==false) + { + this->mo_CShareMemory.Close(); return this->EReturn_ShareMemMapErr; + }/* + if(this->mo_CShareMemory.LinkMap()==false)*/ + + mph_SpinLock = + (pthread_spinlock_t*)mo_CShareMemory.GetStartAddress(); + + return 0; + } + else // mo_CShareMemory.ShmGet(AL_MemMapkey, sizeof(pthread_spinlock_t))!=false + { + if(this->mo_CShareMemory.LinkMap()==false) + { + this->mo_CShareMemory.Close(); return this->EReturn_ShareMemMapErr; + }/* + if(this->mo_CShareMemory.LinkMap()==false)*/ + + mph_SpinLock=(pthread_spinlock_t*)mo_CShareMemory.GetStartAddress(); + + ::memset((void*)mph_SpinLock, 0x00, sizeof(pthread_spinlock_t)); + + return ::pthread_spin_init(mph_SpinLock, PTHREAD_PROCESS_SHARED); + }/* + else // mo_CShareMemory.ShmGet(AL_MemMapkey,sizeof(pthread_spinlock_t))!=false*/ + }/* + int Init(long AL_MemMapkey)*/ + + int Close() + { + mo_CShareMemory.UnMap(); + mo_CShareMemory.Close(); + + return ::pthread_spin_destroy(mph_SpinLock); + }/* + void Close()*/ + + int Lock() + { + return ::pthread_spin_lock(mph_SpinLock); + }/* + void Lock()*/ + + int TryLock() + { + return ::pthread_spin_trylock(mph_SpinLock); + }/* + void TryLock()*/ + + int UnLock() + { + return ::pthread_spin_unlock(mph_SpinLock); + }/* + void UnLock()*/ + + public: + };/* + class ZCSpinLockProcess*/ + + + typedef ZCSpinLock ZCCriticSect; + + +#endif //__USE_XOPEN2K + + + /*////////////////////////////////////////////////////////////////////////////////////// + + http://blog.naver.com/kimsk99?Redirect=Log&logNo=50004383787 + + α׷ ϸ鼭 带 , CreateThread _beginthread Լ +  Լ ؾ ϰ ȴ. ׻ ⺻ API CreateThread + Ծ. ׷ å дٰ װ ߸Ǿٴ ˾Ҵ. MSDN + ڼ о ̾ ڼ ׵ + . ϴ CreateThread SDK ϴ ⺻ API̴. Ư ̺귯 + ũ ʾƵ ϵǰ ư. + + _beginthread(Ǵ _beginthreadex) + + standard C library Լ ũؾ Ѵ. ׷ ɿ + . ɿ ̰ ʴ´ٸ ̷ ̴. + + _beginthread ޶ ʿ + 찡 ִ. ׷ Լ _beginthreadex CreateThread + ڸ ִ. ׷ CreateThread _beginthreadex ġ + ȯ ϴ. + + εۿ ū _beginthread standard C library ϴ + TLB ʱȭ شٴ ̴. standary C library ִ Լ Ϻδ thread- + safety ؼ TLB ϴµ ʱȭ ʴ´ٸ ߻ ִ. + + _beginthreadex Լ ؼ 带 ߴٸ Լ 带 + ϱ ؼ ExitThread Լ ϱ ٴ _endthreadex Լ ϱ Ѵ. + + κ C library ϱ _beginthreadex ؾ + Ѵ. + + uintptr_t _beginthreadex + ( + void *security, + unsigned stack_size, + unsigned ( *start_address )( void * ), + void *arglist, + unsigned initflag, + unsigned *thrdaddr + ); + + HANDLE CreateThread + ( + LPSECURITY_ATTRIBUTES lpThreadAttributes, + SIZE_T dwStackSize, + LPTHREAD_START_ROUTINE AP_StartAddress, + LPVOID lpParameter, + DWORD dwCreationFlags, + LPDWORD lpThreadId + ); + + CreateThread _beginthreadex ü ְ ׷ Ѵ. + + dwCreationFlags + [in] Flags that control the creation of the thread. + If the CREATE_SUSPENDED flag is specified, + the thread is created in a suspended state, + and will not run until the ResumeThread function is called. + If this value is zero, + the thread runs immediately after creation. + If the STACK_SIZE_PARAM_IS_A_RESERVATION flag is specified, + the dwStackSize parameter specifies the initial reserve size of the stack. + Otherwise, dwStackSize specifies the commit size. + + Windows 2000/NT and Windows Me/98/95: + The STACK_SIZE_PARAM_IS_A_RESERVATION flag is not supported. + lpThreadId + [out] Pointer to a variable that receives the thread identifier. + If this parameter is NULL, the thread identifier is not returned. + + Windows Me/98/95: This parameter may not be NULL. + + cf) DWORD ResumeThread( HANDLE hThread ); + + + IN WINBASE.H + + typedef DWORD (WINAPI *PTHREAD_START_ROUTINE) + ( + LPVOID lpThreadParameter + ); + + typedef struct _SECURITY_ATTRIBUTES + { + DWORD nLength; + LPVOID lpSecurityDescriptor; + BOOL bInheritHandle; + } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; + + typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; + + LPTHREAD_START_ROUTINE AP_StartAddress Լ + DWORD WINAPI ThreadFunc(LPVOID lpRarameter) + + MFC ȭ object + + Ʒ object ؼ ʿ + + 1) CCriticalSection cs; + cs.Lock(); + // ۾ڵ + cs.Unlock(); + + 2) CEvent event; + Thread ֵ Ǵ + CEvent object ϰ Thread CallBack Լ + + UINT ThreadFunc(LPVOID pParam) + { + while(TRUE) + { + CEventOvj.Lock(); // ̵. + + // ̺Ʈ ߻ ڵ带 ´. + // ׸ ܺο + // CEventOvj.PulseEvent(); ̳ + // CEventOvj.SetEvent(); ȣϸ . + + // Thread Lock ɷ ¿ + // PulseEvent Լ ȣϸ ƹϵ Ͼ ʰ + // ٷ Lock() ȣϸ ٽ ܴ. + // SetEvent() 쿡 ׳ Ѵ. + } + //while(TRUE) + } + //UINT ThreadFunc(LPVOID pParam) + + + # Window Thread Callback Type; + + DWORD WINAPI ThreadFunc(LPVOID lpParameter); + + cf) typedef unsigned long DWORD; + + # Linux Thread Callback Type: + + void* ThreadFunc()(void*) + + -- MFC ȭ object + + //////////////////////////////////////////////////////////////////////////////////////*/ + + + typedef pthread_t ThreadID; + + + #define _THREAD_RETURN_ void* + + + namespace ZNsIFace + { + class ZCThread_BASE + { + };/* + class ZCThread_BASE*/ + }/* + namespace ZNsIFace*/ + + + template< typename TTypeBase=ZNsMain::ZCEmpty + > + class ZtCThreadAttr : public TTypeBase //////// + { + protected: + pthread_attr_t mh_ThreadAttr; + public : + + ZtCThreadAttr() + { + }/* + ZtCThreadAttr()*/ + + ZtCThreadAttr(TTypeBase& AR_CBaseType):TTypeBase(AR_CBaseType) + { + }/* + ZtCThreadAttr(TTypeBase& AR_CBaseType)*/ + + template + ZtCThreadAttr(const TTypeArg& AR_TTypeArg) : TTypeBase(AR_TTypeArg) + { + }/* + template + ZtCThreadAttr(const TTypeArg& AR_TTypeArg) : TTypeBase(AR_TTypeArg) */ + + pthread_attr_t* GetThreadAttrPtr() + { + return &mh_ThreadAttr ; + }/* + pthread_attr_t* GetThreadAttrPtr()*/ + + int Init() + { + /*//////////////////////////////////////// + + RETURN VALUES + On success, pthread_attr_init() returns 0. On error, + one of the following values is returned: + + ENOMEM + Insufficient memory exists to create the thread attribute object. + + EINVAL + attr does not point to writable memory. + + EFAULT + attr is an invalid pointer + + ////////////////////////////////////////*/ + + return pthread_attr_init(&mh_ThreadAttr); + }/* + int Init()*/ + + int Fini() + { + return pthread_attr_destroy(&mh_ThreadAttr); + }/* + int Fini()*/ + + int GetDetachState(int& ARRI_DetachState) + { + return pthread_attr_getdetachstate(&mh_ThreadAttr, &ARRI_DetachState); + }/* + int GetDetachState(int ARRI_DetachState)*/ + + int SetDetachState(int AI_DetachState=PTHREAD_CREATE_DETACHED) // cf) PTHREAD_CREATE_JOINABLE + { + return pthread_attr_setdetachstate(&mh_ThreadAttr, AI_DetachState); + }/* + int SetDetachState(int AI_DetachState=PTHREAD_CREATE_DETACHED)*/ + + int GetSchedPolicy(int& ARRI_Policy) + { + return pthread_attr_getschedpolicy(&mh_ThreadAttr, &ARRI_Policy); + }/* + int GetSchedPolicy(int ARRI_Policy)*/ + + /*//////////////////////////////////////////////////////////// + + pthread_attr_setschedpolicy() 2 μ 밡 + + SCHED_FIFO + First in-first out (FIFO) scheduling policy. + + SCHED_RR + Round robin scheduling policy. + + SCHED_OTHER + Another scheduling policy + + ////////////////////////////////////////////////////////////*/ + + int SetSchedPolicy(int AI_Policy) + { + return pthread_attr_setschedpolicy(&mh_ThreadAttr, AI_Policy); + }/* + int SetSchedPolicy(int AI_Policy)*/ + + int GetSchedParam(const struct sched_param& ARR_SchedParam) + { + // struct sched_param{int sched_priority;}; + + return pthread_attr_getschedparam(&mh_ThreadAttr, &ARR_SchedParam); + }/* + int GetSchedParam(const struct sched_param& ARR_SchedParam)*/ + + int SetSchedParam(const struct sched_param& AR_SchedParam) + { + return pthread_attr_setschedparam(&mh_ThreadAttr, &AR_SchedParam); + }/* + int SetSchedParam(const struct sched_param& AR_SchedParam)*/ + + int GetStackSize(size_t& ARRI_StackSize) + { + return pthread_attr_getstacksize(&mh_ThreadAttr, &ARRI_StackSize); + }/* + int GetStackSize(size_t& ARRI_StackSize)*/ + + int SetStackSize(size_t AI_StackSize) + { + // PTHREAD_STACK_MIN ̻̾ Ѵ. + + return pthread_attr_setstacksize(&mh_ThreadAttr, AI_StackSize); + }/* + int SetStackSize(size_t AI_StackSize)*/ + + /*///////////////////////////////////////////////////////////////////////// + + ̺ R. Ʈ 'POSIX 带 ̿ α׷' 200 page + + ýۿ _POSIX_THREAD_ATTR_STACKSIZE ȣ ϰ ִٸ, + size_t statcksize Ӽ ִ. + + Ǿ ִµ, CentOS 64 bit + + find /usr/include/ | xargs grep 'POSIX_THREAD_ATTR_STACKSIZE' + + ϸ, + + /usr/include/bits/posix_opt.h:#define _POSIX_THREAD_ATTR_STACKSIZE 200112L + + ã ִ. -- 2011-05-23 20:44:00 + + å, + + POSIX 忡 忡 䱸ϴ ּ ũ⸦ Ÿ + ȣ μ PTHREAD_STACK_MIN Ѵ. + + ȣ CentOS ã bits/local_lim.h + + #define PTHREAD_STACK_MIN 16384 + + Ǿ ִ. -- 2011-05-23 20:55:00 + + /////////////////////////////////////////////////////////////////////////*/ + + public: + };/* + template< typename TTypeBase=ZNsMain::ZCEmpty + > + class ZtCThreadAttr /////////////////////////*/ + + + template< typename TTypeBase=ZNsIFace::ZCThread_BASE + > + class ZtCThread : public TTypeBase /////////////////// + { + protected: + ThreadID mh_ThreadID; + public : + + ZtCThread() + { + _DEBUG_REENTRANT_CHECK_ + + mh_ThreadID = 0 ; + } + ZtCThread(TTypeBase& AR_CBaseType):TTypeBase(AR_CBaseType) + { + _DEBUG_REENTRANT_CHECK_ + } + ZtCThread(const ZtCThread& rhs):TTypeBase(rhs) + { + _DEBUG_REENTRANT_CHECK_ + + mh_ThreadID =rhs.mh_ThreadID ; + (TTypeBase&)(*this)=static_cast(rhs); + } + template + ZtCThread(const TTypeArg& AR_TTypeArg):TTypeBase(AR_TTypeArg) + { + _DEBUG_REENTRANT_CHECK_ + } + ZtCThread& operator=(const ZtCThread& rhs) + { + return *this; + }/* + ZtCThread& operator=(const ZtCThread& rhs)*/ + + + operator ThreadID () const + { + return mh_ThreadID; + }/* + operator ThreadID () const*/ + + ThreadID GetThreadID() const + { + return mh_ThreadID; + }/* + ThreadID GetThreadID() const*/ + + bool Make(void* AP_StartAddress(void*), void* AP_Arg=NULL, pthread_attr_t* AP_ThreadAttr=NULL) + { + return ::pthread_create( /////////////// + &mh_ThreadID , + AP_ThreadAttr , + AP_StartAddress , + AP_Arg + /*/////////*/ ) == 0 ; ///////////////// + }/* + bool Make(void* AP_StartAddress(void*), void* AP_Arg=NULL, pthread_attr_t* AP_ThreadAttr=NULL)*/ + + + // ñ Լ ()Ų. + + bool Wait() + { + return ::pthread_join(mh_ThreadID, NULL)==0 ; + }/* + bool Wait()*/ + + bool Wait(void** APP_ThreadReturn) + { + return ::pthread_join(mh_ThreadID, APP_ThreadReturn)==0 ; + }/* + bool Wait(void** APP_ThreadReturn)*/ + + static bool Wait(ThreadID AI_ThreadIDVar, void** APP_ThreadReturn) + { + return ::pthread_join(AI_ThreadIDVar, APP_ThreadReturn)==0 ; + }/* + static bool Wait(ThreadID AI_ThreadIDVar, void** APP_ThreadReturn)*/ + + + /*//////////////////////////////////////////////////////////////////////////////////// + + pthread_detach μ fork() Ŀ waitpid() ʾƵ ǵ + SIGCHILD ϴ Ͱ ϴ. + + ׸ (::pthread_join) Ÿ, ݵ ȣؾ ϴ . + pthread_detach() ȣ 尡 ߴµ ޸𸮰 OS ȯ + ִ. www.wordncode.com ϼ ڵ带 Ծϸ + Ŭ̾Ʈ ߴµ ޸𸮰 پ ʰ ϴ ̾. ׷ + ()޸𸮸 Ͽ Ŭ̾Ʈ ӽÿ ؼ 带 + ϰ ־! + + -- 2009-02-24 03:08:00 + + ////////////////////////////////////////////////////////////////////////////////////*/ + + static bool Detach(pthread_t AI_ThreadID) + { + return ::pthread_detach(AI_ThreadID)==0; + }/* + static bool Detach(pthread_t AI_ThreadID)*/ + + bool Detach() + { + return ::pthread_detach(mh_ThreadID)==0; + }/* + bool Detach()*/ + + + /*////////////////////////////////////////////////////////////////////////////// + + 带 (pthread_cancel)Ѵٴ ٸ κ ҿû ޾Ƽ + ۵ ϴ ǹմϴ. ġ kill ̿ؼ μ ߴܽŰ + Ͱ մϴ. ׷ ߴ û 尡 ٷ ߴܵǴ°? װ ƴ + ϴ. kill μ ̴ ͵ δ μ ̴ ñ׳ + μ ñ׳ óϿ ׾ ϴµ + ְų Ȥ (deferred) Ǿ ״ 쵵 ߻մϴ. ҵ ̿ + ٷ ׾ ʽϴ. ҵǵ ϴٸ, + ⺻ (deferred) Ҹ ǹմϴ. + + ý Ʈũ α׷ : ǻ : 輱 315 page + + cf) int pthread_setcancelstate(int state,int* oldstate) : Լ + + state PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DISABLE + + //////////////////////////////////////////////////////////////////////////////*/ + + static bool Cancel(pthread_t AI_ThreadID) + { + return ::pthread_cancel(AI_ThreadID)==0; + }/* + static bool Cancel(pthread_t AI_ThreadID)*/ + + bool Cancel() + { + return ::pthread_cancel(mh_ThreadID)==0; + }/* + bool Cancel()*/ + + public: + };/* + template< typename TTypeBase=ZNsIFace::ZCThread_BASE + > + class ZtCThread ////////////////////////////////////*/ + + + template<> class ZtCThread + { + protected: + ThreadID mh_ThreadID; + public : + + ZtCThread() + { + _DEBUG_REENTRANT_CHECK_ + }/* + ZtCThread()*/ + + ZtCThread(const ZtCThread& rhs) + { + mh_ThreadID=rhs.mh_ThreadID; + }/* + ZtCThread(const ZtCThread& rhs)*/ + + ZtCThread& operator=(const ZtCThread& rhs) + { + return *this; // nothing to do + }/* + ZtCThread& operator=(const ZtCThread& rhs)*/ + + operator ThreadID () const + { + return mh_ThreadID; + }/* + operator ThreadID () const*/ + + ThreadID GetThreadID() const + { + return mh_ThreadID; + }/* + ThreadID GetThreadID() const*/ + + bool Make(void* AP_StartAddress(void*), void* AP_Arg=NULL, pthread_attr_t* AP_ThreadAttr=NULL) + { + return ::pthread_create( ////////////// + &mh_ThreadID , + AP_ThreadAttr , + AP_StartAddress , + AP_Arg + /*/////////*/ ) == 0 ; //////////////// + }/* + bool Make(void* AP_StartAddress(void*), void* AP_Arg=NULL, pthread_attr_t* AP_ThreadAttr=NULL)*/ + + bool Wait() + { + return ::pthread_join(mh_ThreadID, NULL)==0 ; + }/* + bool Wait()*/ + + bool Wait(void** APP_ThreadReturn) + { + return ::pthread_join(mh_ThreadID, APP_ThreadReturn)==0 ; + }/* + bool Wait(void** APP_ThreadReturn)*/ + + static bool Wait(ThreadID AI_ThreadIDVar, void** APP_ThreadReturn) + { + return ::pthread_join(AI_ThreadIDVar, APP_ThreadReturn)==0 ; + }/* + static bool Wait(ThreadID AI_ThreadIDVar, void** APP_ThreadReturn)*/ + + static bool Detach(pthread_t AI_ThreadID) + { + return ::pthread_detach(AI_ThreadID)==0; + }/* + static bool Detach(pthread_t AI_ThreadID)*/ + + bool Detach() + { + return ::pthread_detach(mh_ThreadID)==0; + }/* + bool Detach()*/ + + static bool Cancel(pthread_t AI_ThreadID) + { + return ::pthread_cancel(AI_ThreadID)==0; + }/* + static bool Cancel(pthread_t AI_ThreadID)*/ + + bool Cancel() + { + return ::pthread_cancel(mh_ThreadID)==0; + }/* + bool Cancel()*/ + + public: + };/* + template<> class ZtCThread*/ + + + + /*////////////////////////////////////////////////////////////////////////////////////// + + class ZtCMutexCond window ؽ Ǻ Ŭ + + ̰ ټ 尡 Լ A, Լ B, Լ C ϴµ, ݵ + A -> B -> C ؾ ϰ Լ ȭ ־ , + Ǻ ϸ ؽ ϳ (Ǻ 3-1 ), ؽθ Ѵٸ A, + B,C 3 ؽ ؾ Ѵ. ؽ + ִ. ݴ Ǻ ؽ . + + Ǻ ؼ ȵȴ. ڿ Կ ´. + + Ǻ ݵ ѹ ʱȭ Ǿ Ѵ. + +  ۾ ť ټ 尡 Ͽ ۾ ´ٰ . ۾ť ϴ + , ť ϴ ٸ 尡 ʵ '۾ ť + ȭ object ' lock ɰ ش ť ִ ׷ ̴. ̶ + ť ϵ ۾ ϳ ִٸ ۾ '۾ť ȭ object' + unlock ̴. ť ϵ ۾ ٸ '۾ ť ȭ object' unlock + ϰ ڽ ۾ť ۾ ϵ Ǿ Ѵ. ̶ ڽ ǰ ִ + ˸ ǥø ϰ(׷ ߿ '' ϱ) Ǿ ϴµ, + unlock ǥø ϰ Ǵ ̿ ٸ 尡 '۾ť + ȭ object' lock ɰ ۾ ϸ, ۾ и ִµ ǥø Ϸ + ǥø ϱ⵵ ̹Ƿ, ٸ 尡 ǰ ʴٰ + ó '۾ť ȭ object' unlock ϰ ̴. + ׷ ǥøϰ Ƿ ȸ ä + ִ. ¸ ϱ '۾ť ȭ object' unlock ϴ + ۾ · ϴ ̷ Ѵ. ̷ ٸ 尡 + ǰ ִ 带 Ȯϰ Ǻ ְԲ ش. ̰ + ̴. + + ׻ ؽ ä ؾ Ѵ. + ( ϱ , ϰ ؽ ´.) + + ؽ ä 󸶵 Ǻ ñ׳ ų εijƮ + .  尡 Ǻ ñ׳ ų εijƮѴ + 尡 ϳ ٸ ƹϵ Ͼ ʴ´. ٸ + pthread_cond_wait() Լ ȣѴٸ, ٷ ش ñ׳ + ٴ ϰ ٸ ۿ . ٷ + ȵǴ Ȳ̶  ȴ. 尡 Ǻ + ؽ ä ֱ , ˻ ⵵߿(ٸ 鿡 + )  . ؽ Ƿ ٸ + Ÿ ̴. + + ׻  ׽Ʈ϶! ׸ ٽ ѹ ׽Ʈ϶! + + 尡  , ٽ  ׽Ʈϴ ſ ߿ϴ. + ׻ ̿Ͽ ϴ . + + -- ̺ R Ʈ Posix 带 ̿ α׷ 123P + + Ǻ Ư ؽ ǰ յǾ Ѵ. 尡 + ׻ յ ؽ װ ־ Ѵ. Ǻ + , 带 ϱ ؽ ϰ ڵ ϱ ؽ + ٽ ٴٴ + + -- ̺ R Ʈ Posix 带 ̿ α׷ 123P + + window ؽ ϱⰡ 絥, + Ư "" "" Ѵٸ IOCP GetQueuedCompletionStatus() + Լ ̿Ͽ ִ. + + window Ǻ ̺Ʈ ϴ . + + -- 2008-12-05 15:06:00 + + غ Ǻ ߿ ù° "" ° ؽ 尡 + "ٸ 尡 ϴ " ϴ ƴұ Ѵ. + + -- 2007-11-12 07:56:00 + + "۾" Ǻ ϰ ְ, "־" "۾" ñ׳ + غ. "־" "۾" ñ׳ , "۾ + " ؽ Lock ɰ Լ ÷ ̴. ̶ "־" + Lock ɰ ñ׳ ´ٸ, "۾" Լ ϱ ̹ + ؽ Ƿ, ؽ Ǯ ٽ ϰ ȴ. ñ׳ + "־" Lock Ǯ־ Ѵ. ñ׳η  "۾ + " ؽ Lock ɰ Լ ϰ Ǹ ؽ Lock Ǯ + . -- 2007-11-16 05:51:00 + + //////////////////////////////////////////////////////////////////////////////////////*/ + + template< typename TData=ZNsMain::ZCEmpty ///////////// + > + class ZtCMutexCond : public TData, ZNsMain::ZCNonCopyable + { + protected: + ::pthread_cond_t mh_PThread_Cond; + public : + + ::pthread_cond_t GetHandle() const + { + return mh_PThread_Cond; + }/* + ::pthread_cond_t GetHandle() const*/ + + int InitCond(pthread_condattr_t* AP_CondAttr=NULL) + { + return ::pthread_cond_init(&mh_PThread_Cond, AP_CondAttr) ; + + /*///////////////////////////////////////////////////////// + + pthread_cond_init ȯ( 0) + + EAGIN (޸̿) ڿ ϴ. + ENOMEM ޸𸮰 ϴ. + EBUSY Ǻ ̹ ʱȭ Ǿ ִ. + EINVAL AP_CondAttr ùٸ ʴ. + + ̸ ʱȭ Ѵ. (PTHREAD_COND_INITIALIZER) + + /////////////////////////////////////////////////////////*/ + }/* + int Init(pthread_condattr_t* AP_CondAttr=NULL)*/ + + int FiniCond() + { + /*//////////////////////////////////////////////////////////// + + pthread_cond_destroy() + + RETURN VALUES + On success, pthread_cond_destroy() returns 0. + On error, one of the following values is returned: + + EINVAL + cond does not refer to an initialized condition variable. + + EBUSY + The condition variable is in use by another thread (for example, in a condition wait). + EFAULT + cond is an invalid pointer + + PTHREAD_COND_INITIALIZER ũθ Ͽ + ʱȭ Ǻ ı ʾƵ ȴ. + + ////////////////////////////////////////////////////////////*/ + + return ::pthread_cond_destroy(&mh_PThread_Cond) ; + }/* + int FiniCond()*/ + + int WaitCond(pthread_mutex_t& AR_MutexArg) + { + return ::pthread_cond_wait(&mh_PThread_Cond, &AR_MutexArg) ; + + /*////////////////////////////////////////////////////////// + + pthread_cond_wait Լ Ƿ ؽ ʱ + ȭǾ ְ lock Ǿ ־ Ѵ. Լ Ǹ + Լ ο ؽ lock ä + . ׸ ñ׳ Ǹ + ۾ 簳Ѵ. ش ñ׳ ߻ + μ ؽ pthread_cond_wait + Լ ϰ ȴ. pthread_cond_timedwait + Լ ϸ timespec ðŭ ⸦ ϰ + ȴ. ð ñ׳ Ÿ + ƿ ڵ Բ ȴ. + + //////////////////////////////////////////////////////////*/ + }/* + int WaitCond(pthread_mutex_t& AR_MutexArg)*/ + + int WaitCondTime(pthread_mutex_t& AR_MutexArg, struct timespec& AR_Expriation) + { + // time out ̸ ZNsEnum::ZEThread_TimeOut(ETIMEDOUT) ȯѴ. + + return ::pthread_cond_timedwait(&mh_PThread_Cond, &AR_MutexArg, &AR_Expriation) ; + + /*///////////////////////////////////////////////////// + + DESCRIPTION + The pthread_cond_timedwait() + function blocks on the specified condition variable, + which atomically releases the specified mutex + and causes the calling thread to block on the condition variable + The blocked thread may be awakened by a call to pthread_cond_signal() + or pthread_cond_broadcast(), + or if the time specified by abstime is reached. + + This function atomically releases the mutex, + causing the calling thread to block on the condition variable Upon successful completion, + the mutex is locked and owned by the calling thread. + + pthread_cond_timedwait() is the same as pthread_cond_wait(), + except an error is returned + if the system time equals or exceeds the time specified by abstime + before the condition variable is signaled or broadcast, + or if the absolute time specified by abstime has already passed at the time of the call. + When timeouts occur, pthread_cond_timedwait() releases and reacquires the mutex. + + When using condition variables, + there should always be a boolean predicate involving shared variables related to each condition wait. + This predicate should become true only + when the thread should proceed. + Because the return from pthread_cond_timedwait() does not indicate anything about the value of this predicate, + the predicate should be reevaluated on return. + Unwanted wakeups from pthread_cond_timedwait() may occur + (since another thread could have obtained the mutex, + changed the state and released the mutex, + prior to this thread obtaining the mutex); + the reevaluation of the predicate ensures consistency. + + The pthread_cond_timedwait() function is a cancellation point. + If a cancellation request is acted on while in a condition wait + when the cancellation type of a thread is set to deferred, + the mutex is reacquired before calling the first cancellation cleanup handler. + In other words, the thread is unblocked, + allowed to execute up to the point of returning from the call pthread_cond_timedwait(), + but instead of returning to the caller, it performs the thread cancellation. + + -------------------------------------------------------------------------------- + + PARAMETERS + + cond + Is the condition variable to wait on. + + mutex + Is the mutex associated with the condition variable. + + abstime + Is the absolute time at which the wait is cancelled if not signaled or broadcast. + + -------------------------------------------------------------------------------- + + RETURN VALUES + On success, pthread_cond_timedwait() returns 0. + On error, one of the following values is returned: + + EINVAL + cond does not refer to an initialized condition variable, + or mutex does not refer to an initialized mutex. + Different mutexes were specified in multiple waits on cond. + mutex is not owned by the caller. + + EFAULT + cond, mutex, or abstime is an invalid pointer. + + ETIMEDOUT + The specified absolute time has passed. + + -------------------------------------------------------------------------------- + + CONFORMANCE + POSIX P1003.1 (1996) + + -------------------------------------------------------------------------------- + + MULTITHREAD SAFETY LEVEL + MT-safe. + + ///////////////////////////////////////////////////////////////////////////////*/ + }/* + int WaitCondTime(pthread_mutex_t& AR_MutexArg, struct timespec& AR_Expriation)*/ + + int WakeCond() + { + return ::pthread_cond_signal(&mh_PThread_Cond); + }/* + int WakeCond()*/ + + + /*/////////////////////////////////////////////////////////////////////////////// + + pthread_cond_broadcast() Լ ϴ 忡 ñ׳ + . 尡 Ͼ ǹǷ 밳 ߻ ɼ ִ. + ؾ ۾ 10 1 װ + ڿ ٽ Ѵ. ̷  ٽ + · ʿ 带 ߻Ű ȴ.  쿡 + εijƮ ؼ ؾ Ѵ. + + -- ý Ʈũ α׷, 輱 , ǻ + + ///////////////////////////////////////////////////////////////////////////////*/ + + int BoradCast() + { + return ::pthread_cond_broadcast(&mh_PThread_Cond) ; + }/* + int BoradCast()*/ + + public: + };/* + template< typename TData=ZNsMain::ZCEmpty + > + class ZtCMutexCond //////////////////////*/ + + + + /*/////////////////////////////////////////////////////////////// + + mutex Ǻ Ŭ. ZtCMutexCond<> ø + ZCProcessMutex ̿ϸ ȭ ϱ + ؼ ϴ ̴. + + ///////////////////////////////////////////////////////////////*/ + + template< typename TData=ZNsMain::ZCEmpty + > + class ZtCMutexCondData : public TData + { + protected: + pthread_mutex_t mh_Mutex; + pthread_cond_t mh_Cond ; + public : + + int InitCond(const pthread_mutexattr_t* AP_MutexAttr=0, const pthread_condattr_t* AP_CondAttr=0) + { + #if(_CODE_OLD_) + + // ڵ. + + bool VB_IsOK1=::pthread_mutex_init(&mh_Mutex, AP_MutexAttr)==ZNsMain::ZNsEnum::ZEThread_OK; + bool VB_IsOK2=::pthread_cond_init (&mh_Cond, AP_CondAttr )==ZNsMain::ZNsEnum::ZEThread_OK; + + return (VB_IsOK1 && VB_IsOK2) ? ZNsMain::ZNsEnum::ZEThread_OK : ZNsMain::ZNsEnum::ZEThread_Invalid ; + + #else + return ( ::pthread_mutex_init(&mh_Mutex, AP_MutexAttr)==ZNsMain::ZNsEnum::ZEThread_OK && + ::pthread_cond_init (&mh_Cond, AP_CondAttr )==ZNsMain::ZNsEnum::ZEThread_OK + /*///*/ ) ? ZNsMain::ZNsEnum::ZEThread_OK : ZNsMain::ZNsEnum::ZEThread_Invalid ; + #endif + }/* + int Init(const pthread_mutexattr_t* AP_MutexAttr=0, const pthread_condattr_t* AP_CondAttr=0)*/ + + int Lock() + { + return ::pthread_mutex_lock(&mh_Mutex); + }/* + bool Lock()*/ + + int TryLock(const timespec* AP_TimeOut) + { + return ::pthread_mutex_trylock(&mh_Mutex); + }/* + int TryLock(const timespec* AP_TimeOut)*/ + + int UnLock() + { + return ::pthread_mutex_unlock(&mh_Mutex); + }/* + int UnLock()*/ + + int WaitCond() // ش ؽ lock ɷ ־ Ѵ. + { + return ::pthread_cond_wait(&mh_Cond, &mh_Mutex) ; + }/* + int WaitCond()*/ + + #ifdef __USE_XOPEN2K + + int Lock(const timespec* AP_TimeOut) + { + return ::pthread_mutex_timedlock(&mh_Mutex, AP_TimeOut); + }/* + int Lock(const timespec* AP_TimeOut)*/ + + int WaitCondTime(const timespec* AP_TimeOut) + { + return ::pthread_cond_timedwait(&mh_Cond, &mh_Mutex, AP_TimeOut) ; + }/* + int WaitCondTime(const timespec* AP_TimeOut)*/ + + int WaitCondTime(int AI_TimeOutMili) + { + timespec VO_TimeAbs; // ð + timeval VO_TimeNow; + + /*/////////////////////////////////////////////////////// + + timespec + + struct timespec + { + __time_t tv_sec ; // Seconds. + long int tv_nsec; // Nanoseconds. 10 1 , 1 и=1000*1000 + }; + + int gettimeofday( struct timeval *tv, struct timezone *tz); + int settimeofday(const struct timeval *tv,const struct timezone *tz); + + -- linux manual + + struct timeval + { + long tv_sec; // + long tv_usec; // ũ + }; + + struct timezone + { + int tz_minuteswest; // ׸ġ (minutes) + int tz_dsttime; // DST Ÿ + }; + + timezone struct ʴ´; + tz_dsttime ʵ尡 ʴ´. + ݱ ׷ ε libc glibc ̴. + Ŀ ҽ( ̿ܿ) ʵ尡 ̴. + ׷ ̰Ÿ. + + ~~~~~~ + + gettimeofday settimeofday ϸ 0 ϸ, + нÿ -1 Ѵ.(errno ȴ.) + + ///////////////////////////////////////////////////////*/ + + ::gettimeofday(&VO_TimeNow, NULL); + + VO_TimeAbs.tv_sec =VO_TimeNow.tv_sec + (AI_TimeOutMili/1000) ; + VO_TimeAbs.tv_nsec=VO_TimeNow.tv_usec*1000 + (AI_TimeOutMili%1000)*1000*1000 ; + + return ::pthread_cond_timedwait(&mh_Cond, &mh_Mutex, &VO_TimeAbs) ; // return ZEThread_TimeOut if timeout + }/* + int WaitCondTime(int AI_TimeOutMili)*/ + + #endif //__USE_XOPEN2K + + int WakeCond() + { + return ::pthread_cond_signal(&mh_Cond); + }/* + int WakeCond()*/ + + int WakeAllCond() + { + return ::pthread_cond_broadcast(&mh_Cond); + }/* + int WakeAllCond()*/ + + int BroadCast() + { + return WakeAllCond(); + }/* + int BroadCast()*/ + + int FiniCond() + { + #if(_CODE_OLD_) + + // ڵ. + + bool VB_IsOK1=::pthread_cond_destroy (&mh_Cond )==ZNsMain::ZNsEnum::ZEThread_OK; + bool VB_IsOK2=::pthread_mutex_destroy(&mh_Mutex)==ZNsMain::ZNsEnum::ZEThread_OK; + + return (VB_IsOK1 && VB_IsOK2) ? ZNsMain::ZNsEnum::ZEThread_OK : ZNsMain::ZNsEnum::ZEThread_Invalid ; + + #else + + return ( ::pthread_cond_destroy (&mh_Cond )==ZNsMain::ZNsEnum::ZEThread_OK && + ::pthread_mutex_destroy(&mh_Mutex)==ZNsMain::ZNsEnum::ZEThread_OK + /*///*/ ) ? ZNsMain::ZNsEnum::ZEThread_OK : ZNsMain::ZNsEnum::ZEThread_Invalid ; + + #endif + }/* + int FiniCond()*/ + + public: + };/* + template< typename TData=ZNsMain::ZCEmpty + > + class ZtCMutexCondData : public TData ///*/ + + + /*////////////////////////////////////////////////////////////////// + + ZtCEventCond<> ø Window event , Ư ǿ + ϴ 带 Ѳ ؼ ʿϴ. + + Linux pthread_cond_signal() Լ ش ϰ + ִ ϳ . event ȿ + + pthread_cond_broadcast() + + ؾ Ѵ. + + ܼ WakeCond() Լ WakeAllCond() Լ ִ. + + -- 2009-10-25 23:05:00 + + ټ 尡 ϰ ִµ, signal 2 ȸ + 쿡, 2 尡 ٰ + . signal 1 ȸ ߻ÿ context switching Ͼ  + 尡 , ٽ Ѵٸ, 2 ° + signal 尡  ִ ̴. + + -- 2009-10-26 13:18:00 + + //////////////////////////////////////////////////////////////////*/ + + template< typename TData=ZNsMain::ZCEmpty /////// + > + class ZtCEventCond : public ZtCMutexCondData + { + public: + typedef ZtCMutexCondData ZCMutexCondData; + public: + int WakeCond(){return this->WakeAllCond();} + public: + };/* + template< typename TData=ZNsMain::ZCEmpty //////// + > + class ZtCEventCond : public ZtCMutexCondData*/ + + + typedef ZtCEventCond<> CEventCond; + + +#if defined(__USE_XOPEN2K) && !defined(__USE_MUTEX_COND_FOR_BARRIER__) + + template< typename TData=ZNsMain::ZCEmpty + > + class ZtCBarrier : public TData /////////// + { + protected: + bool mb_IsValidID; + ::pthread_barrier_t mh_BarrierID; // 0 ʱȭ . + public : + + ZtCBarrier() + { + mb_IsValidID=false; + }/* + ZtCBarrier()*/ + + bool IsValid() const{return mb_IsValidID;} + + + /*///////////////////////////////////////////////// + + Init() Fini() ϰ ٷ + + if(CBarrierObj.Init(3)==ZNsEnum::ZEBarrier_OK) + + ̷ Ѵ. + + /////////////////////////////////////////////////*/ + + int Init(unsigned AI_Count, const ::pthread_barrierattr_t* AP_Attr=0) + { + #if(_CODE_OLD_) + + if(mb_IsValidID==true) + { + ::pthread_barrier_destroy(&mh_BarrierID); mb_IsValidID=false; + }/* + if(mb_IsValidID==true)*/ + + #endif // _CODE_OLD_ + + int VI_Return = ::pthread_barrier_init(&mh_BarrierID, AP_Attr, AI_Count); + + if(VI_Return==ZNsEnum::ZEBarrier_OK) mb_IsValidID=true; return VI_Return; + }/* + int Init(unsigned AI_Count, const ::pthread_barrierattr_t* AP_Attr=0)*/ + + int Fini() + { + if(mb_IsValidID==false) return ZNsEnum::ZEBarrier_OK; + + mb_IsValidID=false; return ::pthread_barrier_destroy(&mh_BarrierID); + }/* + int Fini()*/ + + + /*//////////////////////////////////////////////////////////////////////////// + + int pthread_barrier_wait(pthread_barrier_t *barrier); + + RETURN VALUE + Upon successful completion, the pthread_barrier_wait() function shall + return PTHREAD_BARRIER_SERIAL_THREAD for a single (arbitrary) thread + synchronized at the barrier and zero for each of the other threads. + Otherwise, an error number shall be returned to indicate the error. + + ERRORS + The pthread_barrier_wait() function may fail if: + + EINVAL The value specified by barrier does not refer to an initialized + barrier object. + + This function shall not return an error code of [EINTR]. + + The following sections are informative. + + ////////////////////////////////////////////////////////////////////////////*/ + + bool Wait() + { + return ::pthread_barrier_wait(&mh_BarrierID)!=ZNsEnum::ZEThread_Invalid; + }/* + bool Wait()*/ + + + // Ʒ 2 쿡 . + + bool GetShared(::pthread_barrierattr_t AH_BarrierAttr, int& ARRI_PShared) + { + return ::pthread_barrierattr_getpshared(&AH_BarrierAttr, &ARRI_PShared)==ZNsEnum::ZEThread_OK; + }/* + bool GetShared(::pthread_barrierattr_t AH_BarrierAttr, int& ARRI_PShared)*/ + + /* cf) PTHREAD_PROCESS_SHARED, PTHREAD_PROCESS_PRIVATE + AI_PShared PTHREAD_PROCESS_SHARED ϴ 쿡 + mh_BarrierID ޸𸮿 ؾ Ѵ. */ + + bool SetShared(::pthread_barrierattr_t AH_BarrierAttr, int AI_PShared=PTHREAD_PROCESS_SHARED) + { + return ::pthread_barrierattr_setpshared(&AH_BarrierAttr, AI_PShared)==ZNsEnum::ZEThread_OK; + }/* + bool SetShared(::pthread_barrierattr_t AH_BarrierAttr, int AI_PShared=PTHREAD_PROCESS_SHARED)*/ + + public: + };/* + template< typename TData=ZNsMain::ZCEmpty + > + class ZtCBarrier : public TData /////////*/ + + +#else // !defined(__USE_XOPEN2K) || defined(__USE_MUTEX_COND_FOR_BARRIER__) + + + template< typename TData=ZNsMain::ZCEmpty + > + class ZtCBarrier : public TData /////////// + { + public : + typedef ZtCMutexCondData<> ZCMutexCondData; + protected: + ZCMutexCondData mo_CCondData; + bool mb_IsValidID; + int mi_WaitCount; + public : + + ZtCBarrier():mi_WaitCount(0){mb_IsValidID=false;} + + bool IsValid() const{return mb_IsValidID;} + + + /*////////////////////////////////////////////////// + + Init() Fini() ϰ ٷ + + if(CBarrierObj.Init(3)==ZNsEnum::ZEBarrier_OK) + + · Ѵ. + + //////////////////////////////////////////////////*/ + + int Init(unsigned AI_Count) + { + if(mb_IsValidID==true) + { + mo_CCondData.FiniCond(); mb_IsValidID=false; + }/* + if(mb_IsValidID==true)*/ + + mi_WaitCount=AI_Count; + + int VI_Return = mo_CCondData.InitCond(); + + if(VI_Return==ZNsEnum::ZEThread_OK) + { + mb_IsValidID=true; return ZNsEnum::ZEThread_OK; + }/* + if(VI_Return==ZNsEnum::ZEThread_OK)*/ + + return ZNsEnum::ZEBarrier_NO; + }/* + int Init(unsigned AI_Count)*/ + + int Fini() + { + if(mb_IsValidID==false) return ZNsEnum::ZEThread_OK; + + mb_IsValidID=false; + mi_WaitCount=0 ; + + return (mo_CCondData.FiniCond()==ZNsEnum::ZEThread_OK) ? + ZNsEnum::ZEBarrier_OK : ZNsEnum::ZEBarrier_NO ; + }/* + int Fini()*/ + + bool Wait() + { + bool VB_IsOK=false; + + mo_CCondData.Lock(); + { + if(--mi_WaitCount<=0) + VB_IsOK=(mo_CCondData.WakeAllCond()==ZNsEnum::ZEThread_OK); + else + VB_IsOK=(mo_CCondData.WaitCond ()==ZNsEnum::ZEThread_OK); + //else + } + mo_CCondData.UnLock(); + + return VB_IsOK; + }/* + bool Wait()*/ + + public: + };/* + template< typename TData=ZNsMain::ZCEmpty + > + class ZtCBarrier : public TData /////////*/ + +#endif // !defined(__USE_XOPEN2K) || defined(__USE_MUTEX_COND_FOR_BARRIER__) + + + typedef ZCSpinLockEasy ZCFastLockEasy; + +}/* +namespace ZNsMain*/ + + + +#ifdef __INC_GLIB_ATOMIC_EXCHANGE__ + + +#include + + +namespace ZNsMain +{ + + /*/////////////////////////////////////////////////////// + + class ZtCAtomicIntSync<> + + Ŀ̳ ̺귯 ȭ object ʰ + ȭ ϰ 쿡 ϴ Ŭ ø. + volatile gint ̿ϰ ִ. + + lock-free . + + int sched_yield(void) : IN + + A process can relinquish the processor voluntarily + without blocking by calling sched_yield(). + The process will then be moved to the end of the queue + for its static priority and a new process gets to run. + + Note: If the current process is the only process + in the highest priority list at that time, + this process will continue + to run after a call to sched_yield(). + + POSIX systems on which sched_yield() is available define _POSIX_PRIORITY_SCHEDULING in . + + RETURN VALUE + + On success, sched_yield() returns 0. + On error, -1 is returned, and errno is set appropriately. + + atomic Լ Ʒ ȸ ִ. + + find /usr/include/ | xargs grep 'atomic' | grep 'add' # or + find /usr/include/ | xargs grep 'atomic' | grep 'increment' + + memory barrier ڵ Ʒ . + + [root@localhost ~]# find /usr/include/ | xargs grep -n 'MEM_BARRIER' | more + + /usr/include/c++/4.1.1/tr1/boost_shared_ptr.h:155: _GLIBCXX_READ_MEM_BARRIER; + /usr/include/c++/4.1.1/tr1/boost_shared_ptr.h:156: _GLIBCXX_WRITE_MEM_BARRIER; + /usr/include/c++/4.1.1/tr1/boost_shared_ptr.h:175: _GLIBCXX_READ_MEM_BARRIER; + /usr/include/c++/4.1.1/tr1/boost_shared_ptr.h:176: _GLIBCXX_WRITE_MEM_BARRIER; + /usr/include/c++/4.1.1/x86_64-redhat-linux/bits/atomic_word.h:42:// #define _GLIBCXX_READ_MEM_BARRIER __asm __volatile ("":::"memory") + /usr/include/c++/4.1.1/x86_64-redhat-linux/bits/atomic_word.h:46:// #define _GLIBCXX_WRITE_MEM_BARRIER __asm __volatile ("":::"memory") + /usr/include/c++/4.1.1/bits/atomicity.h:53:#ifndef _GLIBCXX_READ_MEM_BARRIER + /usr/include/c++/4.1.1/bits/atomicity.h:54:#define _GLIBCXX_READ_MEM_BARRIER __asm __volatile ("":::"memory") + /usr/include/c++/4.1.1/bits/atomicity.h:56:#ifndef _GLIBCXX_WRITE_MEM_BARRIER + /usr/include/c++/4.1.1/bits/atomicity.h:57:#define _GLIBCXX_WRITE_MEM_BARRIER __asm __volatile ("":::"memory") + + glib ִ Ʒ Լ ̿Ѵ. (glib gtk+ ̺귯̴.) + + gboolean g_atomic_int_compare_and_exchange + ( + volatile gint *atomic, + gint oldval , + gint newval + ); + //gboolean g_atomic_int_compare_and_exchange + + Compares oldval with the integer pointed to by atomic and if they are equal, + atomically exchanges *atomic with newval. Also acts as a memory barrier. + + Returns : TRUE, if *atomic was equal oldval. FALSE otherwise + + Ʒ Լ Ѵ. + + gboolean g_atomic_pointer_compare_and_exchange + ( + volatile gpointer *atomic, + gpointer oldval, + gpointer newval + ); + //gboolean g_atomic_pointer_compare_and_exchange + + -- 2010-04-03 18:05:00 + +  ZtCAtomicIntSync<> ȭ object ؼ + (̰) Ǵ , ZtCAtomicIntSync<>::TypeSync Ÿ ؼ +  ȭ object ߴ Ÿ ̴. + + -- 2010-04-17 21:29:00 + + alsa/iatomic.h atomic Լ ֱ ѵ, + glib g_atomic_int_compare_and_exchange() شϴ Լ . + + -- 2011-06-19 22:49:00 + + ( centos)alsa/iatomic.h atomic_add(), atomic_sub() Լ ִ. + + static __inline__ void atomic_add(int i, atomic_t *v) + { + __asm__ __volatile__( + ATOMIC_SMP_LOCK "addl %1,%0" + :"=m" (v->counter) + :"ir" (i), "m" (v->counter)); + } + + static __inline__ void atomic_sub(int i, atomic_t *v) + { + __asm__ __volatile__( + ATOMIC_SMP_LOCK "subl %1,%0" + :"=m" (v->counter) + :"ir" (i), "m" (v->counter)); + } + + -- 2013-06-09 00:16:00 + + ///////////////////////////////////////////////////////*/ + + + template< typename TTypeBase=ZNsMain::ZCEmpty + > + class ZtCAtomicIntSync : public TTypeBase + { + public : + typedef ZtCAtomicIntSync TypeSync; + public : + enum{ZEUseAtomicInt=1}; + public : + + enum ZESync + { + ZESync_Lock =0, + ZESync_UnLock=1 + };/* + enum ZESync*/ + + private: + volatile gint mi_SyncState; + public : + + ZtCAtomicIntSync() + { + mi_SyncState=ZESync_UnLock; + }/* + ZtCAtomicIntSync()*/ + + ZtCAtomicIntSync(const TTypeBase& rhs) : TTypeBase(rhs) + { + mi_SyncState=ZESync_UnLock; + }/* + ZtCAtomicIntSync(const TTypeBase& rhs)*/ + + ZtCAtomicIntSync(const ZtCAtomicIntSync& rhs) : TTypeBase(rhs) + { + mi_SyncState=ZESync_UnLock; + }/* + ZtCAtomicIntSync(const ZtCAtomicIntSync& rhs)*/ + + ZtCAtomicIntSync& operator=(const TTypeBase& rhs) + { + this->TTypeBase::operator=(rhs); return *this; + }/* + ZtCAtomicIntSync& operator=(const TTypeBase& rhs)*/ + + ZtCAtomicIntSync& operator=(const ZtCAtomicIntSync& rhs) + { + this->TTypeBase::operator=(rhs); return *this; + }/* + ZtCAtomicIntSync& operator=(const ZtCAtomicIntSync& rhs)*/ + + void Lock() + { + #define __INTERLOCKED_COMP_EXCHANGE__ \ + ::g_atomic_int_compare_and_exchange(&mi_SyncState, ZESync_UnLock, ZESync_Lock) + + while(__INTERLOCKED_COMP_EXCHANGE__==FALSE) + { + // Lock ɷ ִ ̴. + + ::sched_yield(); + }/* + while(__INTERLOCKED_COMP_EXCHANGE__==FALSE)*/ + + #undef __INTERLOCKED_COMP_EXCHANGE__ + }/* + void Lock()*/ + + void UnLock() + { + mi_SyncState=ZESync_UnLock; + }/* + void UnLock()*/ + + public: + };/* + template< typename TTypeBase=ZNsMain::ZCEmpty + > + class ZtCAtomicIntSync : public TTypeBase ///*/ + +}/* +namespace ZNsMain */ + + +#else // !__INC_GLIB_ATOMIC_EXCHANGE__ + + +namespace ZNsMain +{ + + template< typename TTypeBase=ZNsMain::ZCEmpty + > + class ZtCAtomicIntSync : public TTypeBase + { + public : + typedef ZCThreadMutexEasy TypeSync; + public : + enum{ZEUseAtomicInt=0}; + private: + TypeSync mo_CSyncEasy; + public : + + ZtCAtomicIntSync() + { + }/* + ZtCAtomicIntSync()*/ + + ZtCAtomicIntSync(const TTypeBase& rhs) : TTypeBase(rhs) + { + }/* + ZtCAtomicIntSync(const TTypeBase& rhs)*/ + + ZtCAtomicIntSync(const ZtCAtomicIntSync& rhs) : TTypeBase(rhs) + { + }/* + ZtCAtomicIntSync(const ZtCAtomicIntSync& rhs)*/ + + ZtCAtomicIntSync& operator=(const TTypeBase& rhs) + { + }/* + ZtCAtomicIntSync& operator=(const TTypeBase& rhs)*/ + + ZtCAtomicIntSync& operator=(const ZtCAtomicIntSync& rhs) + { + this->TTypeBase::operator=(rhs); return *this; + }/* + ZtCAtomicIntSync& operator=(const ZtCAtomicIntSync& rhs)*/ + + void Lock() + { + mo_CSyncEasy.Lock(); + }/* + void Lock()*/ + + void UnLock() + { + mo_CSyncEasy.UnLock(); + }/* + void UnLock()*/ + + public: + };/* + template< typename TTypeBase=ZNsMain::ZCEmpty + > + class ZtCAtomicIntSync : public TTypeBase ///*/ + +}/* +namespace ZNsMain */ + + +#endif //!__INC_GLIB_ATOMIC_EXCHANGE__ + + +#endif //__ZCPPMAIN__PROCESS_LINUX_H__ diff --git a/ZCppMain/ZCProcess_Win.H b/ZCppMain/ZCProcess_Win.H new file mode 100644 index 0000000..baa35fc --- /dev/null +++ b/ZCppMain/ZCProcess_Win.H @@ -0,0 +1,3151 @@ + + +#ifndef __ZCPPMAIN__PROCESS_WIN_H__ +#define __ZCPPMAIN__PROCESS_WIN_H__ + +#include "ZCppMain/ZMainHead.H" +#include +#include +#include + + +namespace ZNsMain +{ + + namespace ZNsEnum + { + + /* In WinNT : #define STATUS_WAIT_0 ((DWORD )0x00000000L) + In WinBase : #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) + + Լ 쿡 å , ZEThread_Invalid + ̿ ȯ ִ. */ + + enum ZEThread + { + ZEThread_OK = 0, // =WAIT_OBJECT_0 + ZEThread_Invalid =-1, // Լ . + ZEThread_TimeOut = WAIT_TIMEOUT + };/* + enum ZEThread*/ + + + /*################################################## + + barrier ǥ ȯ. + + barrier üũ + + BarrierClass VO_BarrierClass; + + if(VO_BarrierClass.Init()==ZEBarrier_NO) + { + // some code + } + + . + + if(VO_BarrierClass.Init()!=ZEBarrier_OK) + { + // some code + } + + ؾ ϴ. + + ##################################################*/ + + + enum ZEBarrier + { + ZEBarrier_NO = false , + ZEBarrier_OK = true + };/* + enum ZEBarrier*/ + + }/* + namespace ZNsEnum*/ + + + class ZCProcess + { + protected: + STARTUPINFO mo_SI; + PROCESS_INFORMATION mo_PI; + public : + + bool Exec(LPCTSTR AP_ExeName, LPCTSTR APC_WorkDir=NULL, bool AB_Inherit=TRUE) + { + ::GetStartupInfoA(&mo_SI); return ::CreateProcessA( + NULL , + (LPSTR)AP_ExeName, // Name of app to launch + NULL , // Default process security attributes + NULL , // Default thread security attributes + AB_Inherit , // Inherit handles from the parent + 0 , // Normal priority + NULL , // Use the same environment as the parent + APC_WorkDir , // Launch in the current directory + &mo_SI , // Startup Information + &mo_PI // Process information stored upon return + /*/////////*/ ) == TRUE ; + }/* + bool Exec(LPCTSTR AP_ExeName, LPCTSTR APC_WorkDir=NULL, bool AB_Inherit=TRUE)*/ + + HANDLE GetNowProcessHandle() + { + return ::GetCurrentProcess(); + }/* + HANDLE GetNowProcessHandle()*/ + + static long GetPID() + { + return ::GetCurrentProcessId(); // DWORD GetCurrentProcessId(VOID); + }/* + static long GetPID()*/ + + STARTUPINFO& GetStartUpInfo() + { + return mo_SI; + }/* + STARTUPINFO& GetStartUpInfo()*/ + + PROCESS_INFORMATION& GetProcInfo() + { + return mo_PI; + }/* + PROCESS_INFORMATION& GetProcInfo()*/ + + public: + };/* + class ZCProcess*/ + + + ////////////////////////////////////////// + + /////////// end class ZCProcess /////////// + + ////////////////////////////////////////// + + + + // Memory Map class + + class ZCMemMap + { + private: + HANDLE mh_MemMap; + public : + + ZCMemMap() + { + mh_MemMap=NULL; + }/* + ZCMemMap()*/ + + + /*//////////////////////////////////////////////////////////////////////////// + + ZTypLong ALL_Size 0 ̸ AH_File ũⰡ ״ ȴ. + AH_File ִ ALL_Size 1 ̻ ؾ + . AH_File ȿ ̰ ALL_Size 1 ̻ ̸ AH_File + ũⰡ ALL_Size ȴ. + + ////////////////////////////////////////////////////////////////////////////*/ + + bool Create(HANDLE AH_File=INVALID_HANDLE_VALUE, ZTypLong ALL_Size=0, DWORD ADW_ProtectFlag=PAGE_READWRITE, ::LPSECURITY_ATTRIBUTES AP_FileMappingAttributes=NULL, LPCTSTR AP_Name=NULL) + { + ::LARGE_INTEGER LI; LI.QuadPart=ALL_Size; return (mh_MemMap=::CreateFileMapping( + AH_File, AP_FileMappingAttributes, ADW_ProtectFlag, LI.HighPart, LI.LowPart, AP_Name))!=NULL; + }/* + bool Create(HANDLE AH_File=INVALID_HANDLE_VALUE, ZTypLong ALL_Size=0, DWORD ADW_ProtectFlag=PAGE_READWRITE, ::LPSECURITY_ATTRIBUTES AP_FileMappingAttributes=NULL, LPCTSTR AP_Name=NULL)*/ + + + /* LPVOID AP_BaseAddress Ѵٸ system's memory allocation granularity Ѵ. + granularity ˱ ؼ GetSystemInfo Ѵ. VOID GetSystemInfo(LPSYSTEM_INFO lpSystemInfo) + . NULL ̸ ý ˾Ƽ Ѵ. */ + + /* DWORD ADW_MapSize 0 ̸ ü map ȴ. */ + + LPVOID LinkMap(ZTypLong ALL_Offset=0, DWORD ADW_MapSize=0, DWORD ADW_DesiredAccess=FILE_MAP_ALL_ACCESS, LPVOID AP_BaseAddress=NULL) const + { + ::LARGE_INTEGER LI; LI.QuadPart=ALL_Offset; return ::MapViewOfFileEx( + mh_MemMap, ADW_DesiredAccess, LI.HighPart, LI.LowPart, ADW_MapSize, AP_BaseAddress); + }/* + LPVOID LinkMap(ZTypLong ALL_Offset=0, DWORD ADW_MapSize=0, DWORD ADW_DesiredAccess=FILE_MAP_ALL_ACCESS, LPVOID AP_BaseAddress=NULL) const*/ + + bool UnMap(LPCVOID AP_BaseAddress) const + { + return ::UnmapViewOfFile((void*)AP_BaseAddress)==TRUE; + }/* + bool UnMap(LPCVOID AP_BaseAddress) const*/ + + /* cygwin ̳ mingw ̻ϰ ::UnmapViewOfFile(void*) ǵǾ ִ. + ׷ UnMap() μ (void*)AP_BaseAddress ȯְ ִ. */ + + bool Close() + { + const bool CB_IsOK = (::CloseHandle(mh_MemMap)==TRUE); mh_MemMap=NULL; return CB_IsOK; + }/* + bool Close()*/ + + public: + };/* + class ZCMemMap*/ + + + // ޸ Ŭ + + class ZCShareMemory + { + private: + ZTypeID mh_FileMap; + void* mp_Address; + public : + + ZCShareMemory() + { + mh_FileMap=0; + mp_Address=0; + }/* + ZCShareMemory()*/ + + ZTypeID GetID() const + { + return mh_FileMap; + }/* + ZTypeID GetID() const*/ + + bool IsValidID() const + { + return mh_FileMap!=0; + }/* + bool IsValidID() const*/ + + void* GetStartAddress() const + { + return mp_Address; + }/* + void* GetStartAddress() const*/ + + + // Create() ȣ LinkMap() ȣؾ Ѵ. + + bool Create(LPCTSTR AP_MapName, long AL_MapSize) + { + return (mh_FileMap = ::CreateFileMapping( + INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, AL_MapSize, AP_MapName))!=NULL ; + + /*////////////////////////////////////////////////////// + + HANDLE CreateFileMapping + ( + HANDLE hFile, + LPSECURITY_ATTRIBUTES lpAttributes, + DWORD flProtect, + DWORD dwMaximumSizeHigh, + DWORD dwMaximumSizeLow, + LPCTSTR lpName + ); + + lpName + + The name of the file mapping object. + If this parameter matches the name of an existing mapping object, + the function requests access to the object with the protection that flProtect specifies. + + If this parameter is NULL, + the file mapping object is created without a name. + + If lpName matches the name of an existing event, semaphore, + mutex, waitable timer, or job object, + the function fails, + and the GetLastError function returns ERROR_INVALID_HANDLE. + This occurs because these objects share the same namespace. + + -- lpName ̸ event, semaphore, mutex, waitable timer  + -- ϰ ִٸ GetLastError Լ ERROR_INVALID_HANDLE ȯѴ. + -- NULL ִ. + + Return Value + + If the function succeeds, + the return value is a handle to the file mapping object. + + If the object exists before the function call, + the function returns a handle to the existing object + (with its current size, not the specified size), + and GetLastError returns ERROR_ALREADY_EXISTS. + + If the function fails, the return value is NULL. + To get extended error information, call GetLastError. + + //////////////////////////////////////////////////////*/ + }/* + bool Create(LPCTSTR AP_MapName, long AL_MapSize)*/ + + bool Create(long AL_MapSize) + { + return this->Create(NULL/*lpMapName*/, AL_MapSize); + }/* + bool Create(long AL_MapSize)*/ + + + /*/////////////////////////////////////////////////////////////////////////////// + + LPVOID MapViewOfFile + ( + HANDLE hFileMappingObject , + DWORD dwDesiredAccess , + DWORD dwFileOffsetHigh , + DWORD dwFileOffsetLow , + DWORD dwNumberOfBytesToMap + ); + + hFileMappingObject + + FILE_MAP_ALL_ACCESS + Equivalent to FILE_MAP_WRITE and FILE_MAP_READ. + The object must have been created with the PAGE_READWRITE option. + + FILE_MAP_COPY + A copy-on-write view of the file is mapped. + The object must have been created with the PAGE_WRITECOPY option. + + If the file mapping object is backed by the operating system paging file, + the system commits physical storage from the paging file at the time + that MapViewOfFile is called. + The actual physical storage is not used + until a thread in the process writes to an address in the view. + At that time, the system copies the original page to a new page that is backed + by the paging file, maps the page into the process address space, + and changes the page protection to PAGE_READWRITE. + The threads in the process can access only the local copy of the data, + not the original data. + If the page is ever trimmed from the working set of the process, + it can be written to the paging file storage that is committed + when MapViewOfFile is called. + + This process only allocates physical memory + when a virtual address is actually written to. + Changes are never written back to the original file, + and are freed when the thread in your process unmaps the view. + + Paging file space for the entire view is committed + when copy-on-write access is specified, + because the thread in the process can write to every single page. + Therefore, enough physical storage space must be obtained + at the time MapViewOfFile is called. + + FILE_MAP_EXECUTE + An executable view of the file is mapped (mapped memory can be run as code). + The object must have been created with the PAGE_EXECUTE_READWRITE or PAGE_EXECUTE_READ option. + + Windows Server 2003 and Windows XP: + This value is available starting with Windows XP SP2 and Windows Server 2003 SP1. + Windows 2000: This value is not supported. + + -- FILE_MAP_EXECUTE Ȯ ϴ 𸣰ڴ. + -- ڵμ ִٴ , ڵ  ϴ ΰ. + -- 2008-02-08 21:48:00 + + FILE_MAP_READ + A read-only view of the file is mapped. + The object must have been created with the PAGE_READWRITE or PAGE_READONLY option. + + FILE_MAP_WRITE + A read/write view of the file is mapped. + The object must have been created with the PAGE_READWRITE option. + + dwFileOffsetHigh + A high-order DWORD of the file offset where the view begins. + + dwFileOffsetLow + A low-order DWORD of the file offset where the view is to begin. + The combination of the high and low offsets must specify an offset within the file mapping. + They must also match the memory allocation granularity of the system. + That is, the offset must be a multiple of the allocation granularity. + To obtain the memory allocation granularity of the system, + use the GetSystemInfo function, + which fills in the members of a SYSTEM_INFO structure. + + dwNumberOfBytesToMap + The number of bytes of a file mapping to map to the view. + All bytes must be within the maximum size specified by CreateFileMapping. + If this parameter is 0 (zero), + the mapping extends from the specified offset to the end of the file mapping. + + ///////////////////////////////////////////////////////////////////////////////*/ + + bool LinkMap(DWORD dwDesiredAccess=FILE_MAP_ALL_ACCESS, DWORD dwNumberOfBytesToMap=0) + { + return (mp_Address=::MapViewOfFile(mh_FileMap, dwDesiredAccess, 0, 0, dwNumberOfBytesToMap))!=0 ; + }/* + bool LinkMap(DWORD dwDesiredAccess=FILE_MAP_ALL_ACCESS, DWORD dwNumberOfBytesToMap=0)*/ + + bool UnMap() + { + bool VB_IsOK = + (::UnmapViewOfFile(mp_Address)==TRUE) ; + + mp_Address=0; return VB_IsOK; + }/* + bool UnMap()*/ + + bool Close() + { + bool VB_IsOK = + (::CloseHandle(mh_FileMap)==TRUE); + + mh_FileMap=0; return VB_IsOK; + }/* + bool Close()*/ + + public: + };/* + class ZCShareMemory*/ + + + + /////////////////////////////////////////////// + + /////////// end class ZCShareMemory /////////// + + /////////////////////////////////////////////// + + + + /*////////////////////////////////////////////////////////////////////////////// + + class ZCProcessMutex μ ؽ. + + Window ̸ִ mutex Linux  + ͵ ̴. pthread ̺귯 Ἥ ޸𸮿 mutex Ÿ +  ټ ϴ. Linux ߾忡 + μ  ٸ. Ȯ pthread μ mutex + ʴ´. (2006-12-28 16:02:00) + + window ؽ '' ־ ؽ ؾ Ѵ. + ؽ ReleaseMutex(ؽ) ϸ FALSE ȯѴ. + ش ؽ ؽ ƹ ɾ ī + Ʈ ö ʴ´. īƮŭ ־ Ѵ. + + //////////////////////////////////////////////////////////////////////////////*/ + + class ZCProcessMutex + { + private: + ZTypeID mh_Mutex; + public : + + ZCProcessMutex() + { + mh_Mutex=0; + }/* + ZCProcessMutex()*/ + + ZTypeID GetHandle() const + { + return mh_Mutex; + }/* + ZTypeID GetHandle() const*/ + + bool Make(LPCTSTR AP_MutexName=NULL, LPSECURITY_ATTRIBUTES lpMutexAttributes=NULL, BOOL bInitialOwner=FALSE) + { + if(lpMutexAttributes==NULL) + { + // Mutex ڵ ϵ μ ְ Ѵ. + + SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES_Obj; + SECURITY_ATTRIBUTES_Obj.bInheritHandle =TRUE; + SECURITY_ATTRIBUTES_Obj.lpSecurityDescriptor=NULL; + SECURITY_ATTRIBUTES_Obj.nLength =sizeof(SECURITY_ATTRIBUTES); + + return (mh_Mutex = ::CreateMutex(&SECURITY_ATTRIBUTES_Obj, bInitialOwner, AP_MutexName))!=NULL ; + }/* + if(lpMutexAttributes==NULL)*/ + + return (mh_Mutex = ::CreateMutex(lpMutexAttributes, bInitialOwner, AP_MutexName))!=NULL ; + }/* + bool Make(LPCTSTR AP_MutexName=NULL, LPSECURITY_ATTRIBUTES lpMutexAttributes=NULL, BOOL bInitialOwner=FALSE)*/ + + bool Lock(DWORD ADW_TimeOut=INFINITE) + { + DWORD VI_Return=::WaitForSingleObject(mh_Mutex, ADW_TimeOut); + + return VI_Return!=WAIT_ABANDONED && VI_Return!=WAIT_FAILED ; + + /*/////////////////////////////////////////////////////////////////////////// + + WaitForSingleObject() Լ ش ؽ ȣ° ƴϸ ȣ· + ְ ٷ , ȣ̸ ȣ° Ѵ. + + 尡 ý ϸ ؽ ٸ ٸ + ° ȴ. ׷ ؽ 尡  + ؽ Ǯ ϰ Ǹ ؽ(Abandoned Mutex) Ҹ. + WaitForSingleObject() Լ ϰ WAIT_ABANDONED ޹޴ ̸ + ؽ  ó ΰ α׷ӿ ޸ ̴. + ̰ Critical Section ణ ġ ִ. + + ///////////////////////////////////////////////////////////////////////////*/ + }/* + bool Lock(DWORD ADW_TimeOut=INFINITE)*/ + + int LockRaw(DWORD ADW_TimeOut=INFINITE) + { + return ::WaitForSingleObject(mh_Mutex, ADW_TimeOut); + }/* + int LockRaw(DWORD ADW_TimeOut=INFINITE)*/ + + int LockTime(DWORD AI_TimeOutMili) + { + return LockRaw(AI_TimeOutMili); + }/* + int LockTime(DWORD AI_TimeOutMili)*/ + + bool UnLock() + { + return ::ReleaseMutex(mh_Mutex)==TRUE ; + }/* + bool UnLock()*/ + + bool Close() + { + bool VB_Result=(::CloseHandle(mh_Mutex)==TRUE) ; + + mh_Mutex=0; return VB_Result; + }/* + bool Close()*/ + + public: + };/* + class ZCProcessMutex*/ + + + /////////////////////////////////////////////// + + /////////// end class ZCProcessMutex /////////// + + /////////////////////////////////////////////// + + + class ZCProcessMutexEasy : protected ZCProcessMutex + { + public: + + ZCProcessMutexEasy(LPCTSTR AP_MutexName) + { + if(this->ZCProcessMutex::Make(AP_MutexName)==false) + { + std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); + fileout<ZCProcessMutex::Make(AP_MutexName)==false)*/ + }/* + ZCProcessMutexEasy(LPCTSTR AP_MutexName)*/ + + ZCProcessMutexEasy() + { + if(this->ZCProcessMutex::Make()==false) + { + std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); + fileout<ZCProcessMutex::Make()==false)*/ + }/* + ZCProcessMutexEasy()*/ + + + /*////////////////////////////////////////////////////////// + + Ʒ ٿ ZCProcessMutex() Ϳ ؼ + CProcess_Linux.H class ZZCThreadMutexEasy ּ . + + -- 2013-05-05 07:05:00 + + //////////////////////////////////////////////////////////*/ + + ZCProcessMutexEasy(const ZCProcessMutexEasy& rhs) : ZCProcessMutex() + { + if(this->ZCProcessMutex::Make()==false) + { + std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); + fileout<ZCProcessMutex::Make()==false)*/ + }/* + ZCProcessMutexEasy(const ZCProcessMutexEasy& rhs)*/ + + ~ZCProcessMutexEasy() + { + if(this->ZCProcessMutex::Close()==false) + { + std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); + fileout<ZCProcessMutex::Close()==false)*/ + }/* + ~ZCProcessMutexEasy()*/ + + + using ZCProcessMutex::Lock ; + using ZCProcessMutex::UnLock; + + + public: + };/* + class ZCProcessMutexEasy*/ + + + typedef ZCProcessMutexEasy ZZCThreadMutexEasy; + + + /*///////////////////////////////////////////////////////////// + + class ZCProcessSemaphore μ ȭ object. + μ ȭ Semaphore ְ Window + μ ȭ Mutex ִ. + μ ȭ ̴ Semaphore ȭ ̴ +  Լ ٸ. + + class ZCThreadSemaphore ȣȯDZ + ƴ. ȣȯ ؼ class ZCProcessSemaphore + . 쿡 ̸ִ semaphore μ + ̴. + + ReleaseSemaphore() Լ ϴ ڿ 2 ̻ + ϴ ǰ ִ 尡 2 ̻  + ƴϴ. ݵ 忡 ڽ ŭ + ־ Ѵ. Posix barrier Ȯ + . + + /////////////////////////////////////////////////////////////*/ + + class ZCProcessSemaphore + { + private: + ZTypeID mh_Semaphore; + public : + + ZCProcessSemaphore() + { + mh_Semaphore=0; + }/* + ZCProcessSemaphore()*/ + + ~ZCProcessSemaphore() + { + Close(); + }/* + ZCProcessSemaphore*/ + + bool Make(LPCSTR AP_SemaName, LONG AL_InitialCnt, LONG AL_MaximumCount, LPSECURITY_ATTRIBUTES AP_SemaphoreAttributes=NULL) + { + /*///////////////////////////////////////////////////////////////// + + cf) CreateSemaphore() + + Return Values + If the function succeeds, + the return value is a handle to the semaphore object. + If the named semaphore object existed before the function call, + the function returns a handle to the existing object + and GetLastError returns ERROR_ALREADY_EXISTS. + If the function fails, the return value is NULL. + To get extended error information, call GetLastError. + + /////////////////////////////////////////////////////////////////*/ + + return (mh_Semaphore = ::CreateSemaphoreA( + AP_SemaphoreAttributes, AL_InitialCnt, AL_MaximumCount, AP_SemaName))!=(HANDLE)ERROR_INVALID_HANDLE ; + }/* + bool Make(LPCSTR AP_SemaName,LONG AL_InitialCnt, LONG AL_MaximumCount, LPSECURITY_ATTRIBUTES AP_SemaphoreAttributes=NULL)*/ + + bool Make(LPCSTR AP_SemaName, LONG AL_InitialCnt, LPSECURITY_ATTRIBUTES AP_SemaphoreAttributes=NULL) + { + return (mh_Semaphore = ::CreateSemaphoreA( + AP_SemaphoreAttributes, AL_InitialCnt, AL_InitialCnt, AP_SemaName))!=(HANDLE)ERROR_INVALID_HANDLE ; + }/* + bool Make(LPCSTR AP_SemaName, LONG AL_InitialCnt, LPSECURITY_ATTRIBUTES AP_SemaphoreAttributes=NULL)*/ + + + // Ʒ ؽó 쿡 Ѵ. + + bool Make(LONG AL_InitialCnt=1, LONG AL_MaxCnt=1, LPSECURITY_ATTRIBUTES AP_SemaphoreAttributes=NULL) + { + return (mh_Semaphore=::CreateSemaphore( + AP_SemaphoreAttributes, AL_InitialCnt, AL_MaxCnt, this->GetUniqueSemaKey()) )!=(HANDLE)ERROR_INVALID_HANDLE ; + }/* + bool Make(LONG AL_InitialCnt=1, LONG AL_MaxCnt=1, LPSECURITY_ATTRIBUTES AP_SemaphoreAttributes=NULL)*/ + + + bool MakeZero(LPCSTR AP_SemaName=NULL) // ȣ  . + { + const int CI_MaxNumSemaphore=2100000000; + + return (mh_Semaphore=::CreateSemaphoreA( + NULL, 0, CI_MaxNumSemaphore, AP_SemaName))!=(HANDLE)ERROR_INVALID_HANDLE ; + }/* + bool MakeZero(LPCSTR AP_SemaName=NULL)*/ + + static LPCSTR GetUniqueSemaKey() + { + static long SL_UniqueID=0 ; + const long CL_AddID =100000; + + long VL_UniqueLong = ( SL_UniqueID += CL_AddID ) + ::GetCurrentProcessId() ; + + static char VCA_Buff[100]; ::wsprintf(VCA_Buff, _T("SemaKey%ld"), VL_UniqueLong); return VCA_Buff; + }/* + static LPCSTR GetUniqueSemaKey()*/ + + + /* bool MakeStd() class ZCProcessSemaphore + Window, Linux ʿ ȣȯϱ */ + + bool MakeStd(LPCSTR AP_SemaName, LONG AL_InitialCnt,LONG AL_MaximumCount) + { + return this->Make(AP_SemaName, AL_InitialCnt, AL_MaximumCount); + }/* + bool MakeStd(LPCSTR AP_SemaName, LONG AL_InitialCnt, LONG AL_MaximumCount)*/ + + bool Open(LPCSTR AP_SemaName, DWORD dwDesireAccess=SEMAPHORE_ALL_ACCESS, BOOL bInheritHandle=TRUE) + { + return (mh_Semaphore=::OpenSemaphore(dwDesireAccess, bInheritHandle, AP_SemaName))!=NULL ; + }/* + bool Open(LPCSTR AP_SemaName, DWORD dwDesireAccess=SEMAPHORE_ALL_ACCESS, BOOL bInheritHandle=TRUE)*/ + + + /* ´. Լ ۰ ڽ ڽ + ٰ ϰ ִ. 'API ' 1101 . + + Լ ʿϳĐ  + ʿϴ. -- 2015-09-16 00:40:00 */ + + static int GetValue(HANDLE AH_Sema) + { + if(::WaitForSingleObject(AH_Sema, 0)==WAIT_TIMEOUT) return 0; + + LONG VL_Count=0; ::ReleaseSemaphore(AH_Sema, 1, &VL_Count); + + return VL_Count+1; /*#####################################*/ + }/* + static int GetValue(HANDLE AH_Sema)*/ + + int GetValue() const + { + return GetValue(mh_Semaphore); + }/* + int GetValue() const*/ + + bool IsZeroCount() + { + return ::WaitForSingleObject(mh_Semaphore, 0)==WAIT_TIMEOUT; + }/* + bool IsZeroCount()*/ + + + // cf) WaitForSingleObject() ðʰ 쿡 WAIT_TIMEOUT Ѵ. + + bool Lock(DWORD ADW_TimeOut=INFINITE) + { + return ::WaitForSingleObject(mh_Semaphore, ADW_TimeOut)!=WAIT_FAILED; + }/* + bool Lock(DWORD ADW_TimeOut=INFINITE)*/ + + + /* LockRaw() ̸ ZEThread_OK, ðʰ ZEThread_TimeOut ȯѴ. + Posix  . */ + + int LockRaw(DWORD ADW_TimeOut=INFINITE) + { + return ::WaitForSingleObject(mh_Semaphore, ADW_TimeOut); + }/* + int LockRaw(DWORD ADW_TimeOut=INFINITE)*/ + + int LockTime(DWORD AI_TimeOutMili) + { + return LockRaw(AI_TimeOutMili); + }/* + int LockTime(DWORD AI_TimeOutMili)*/ + + + bool UnLock(LONG lReleaseCount=1, LPLONG lpPreviousCount=NULL) + { + /* cf) lReleaseCount + + [in] Amount by which the semaphore object's current count is to be increased. + The value must be greater than zero. + If the specified amount would cause the semaphore's count to exceed the maximum count + that was specified when the semaphore was created, + the count is not changed and the function returns FALSE. */ + + return ::ReleaseSemaphore(mh_Semaphore, lReleaseCount, lpPreviousCount)!=0 ; + }/* + bool UnLock(LONG lReleaseCount=1, LPLONG lpPreviousCount=NULL)*/ + + bool Close() + { + if(mh_Semaphore==0) return true; + + const bool CB_IsOK =( + ::CloseHandle(mh_Semaphore)==TRUE) ; mh_Semaphore=0; + + return CB_IsOK; + }/* + bool Close()*/ + + public: + };/* + class ZCProcessSemaphore*/ + + + + //////////////////////////////////////////////// + + /////////// end class ZCProcessMutex /////////// + + //////////////////////////////////////////////// + + + + /*////////////////////////////////////////////// + + 쿡 μ +  ʿ䰡 . + + 忡 ::EnterCriticalSection() + ߺ ȣ ʴ´. Mutex + . + + //////////////////////////////////////////////*/ + + typedef ZCProcessSemaphore ZCThreadSemaphore; + typedef ZCProcessMutex ZCThreadMutex ; + typedef ZCProcessMutex ZCThreadMutexStd ; + + + + // posix spin lock Ѵ. + + class ZCCriticSect // Critical Section + { + private: + CRITICAL_SECTION mo_CriticSect; + public : + + void Init() + { + ::InitializeCriticalSection(&mo_CriticSect); + }/* + void Init()*/ + + bool Init(DWORD AI_SpinCount) + { + return ::InitializeCriticalSectionAndSpinCount(&mo_CriticSect, AI_SpinCount)==TRUE; + }/* + bool Init(DWORD AI_SpinCount)*/ + + void Fini() + { + ::DeleteCriticalSection(&mo_CriticSect); + }/* + void Fini()*/ + + void Lock (){::EnterCriticalSection(&mo_CriticSect);} + void UnLock(){::LeaveCriticalSection(&mo_CriticSect);} + + /*////////////////////////////////////////////////////////////////////////////////// + + ̻ϰ TryEnterCriticalSection Լ ȣ . -- 2007-05-17 14:34:00) + + bool TryLock() + { + return TryEnterCriticalSection(&mo_CriticSect)==TRUE; + } + + /////////////////////////////////////////////////////////////////////////////////////*/ + + + #if defined(__VISUAL_CPP_VER__) && __VISUAL_CPP_VER__>=200800 + + bool WaitCond(::PCONDITION_VARIABLE AP_Cond, DWORD AI_Mili=INFINITE) + { + return ::SleepConditionVariableCS(AP_Cond, &mo_CriticSect, AI_Mili)==TRUE; + }/* + bool WaitCond(::PCONDITION_VARIABLE AP_Cond, DWORD AI_Mili=INFINITE)*/ + + #endif //defined(__VISUAL_CPP_VER__) && __VISUAL_CPP_VER__>=200800 + + public: + };/* + class ZCCriticSect*/ + + + class ZCCriticSectEasy : protected ZCCriticSect + { + public: + + ZCCriticSectEasy(){this->Init();} + ZCCriticSectEasy(const ZCCriticSectEasy&){this->Init();} + + ~ZCCriticSectEasy(){this->Fini();} + + void Lock (){this->ZCCriticSect::Lock ();} + void UnLock(){this->ZCCriticSect::UnLock();} + + public: + };/* + class ZCCriticSectEasy : public ZCCriticSect*/ + + + + typedef ZCCriticSectEasy ZCDefLockEasy ; + typedef ZCCriticSectEasy ZCFastLockEasy; + + + template class ZtCAutoKeyRev; + + + /* ZtCAutoKey<> ø Lock ϰ Ѵ. + ִ Key Ͽ. + + ̷ RAII(Resource Acquisition Is Initialization) + Ѵٴ ˾Ҵ. -- 2015-03-10 15:08:00 + */ + template class ZtCAutoKey + { + public : + template friend class ZtCAutoKeyRev; + private: + ZtCAutoKey(const ZtCAutoKey& rhs){} + private: + + TCriticSectEasy& mr_SyncEasy; + + #ifdef _DEBUG_CAUTOKEY_ + static int msi_CallCnt; + #endif //_DEBUG_CAUTOKEY_ + + public: + + ZtCAutoKey(TCriticSectEasy& AR_SyncEasy):mr_SyncEasy(AR_SyncEasy) + { + #ifdef _DEBUG_CAUTOKEY_ + cout<<" ZtCAutoKey:: ZtCAutoKey() "< class ZtCAutoKey */ + + #ifdef _DEBUG_CAUTOKEY_ + + template + int ZtCAutoKey::msi_CallCnt = 0; + + #endif //_DEBUG_CAUTOKEY_ + + + /*//////////////////////////////////////////////////////////////// + + ZtCAutoKeyRev<> ZtCAutoKey<> ڿ μ ޾Ƽ + ڿ Lock ϰ, Ҹڿ ٽ Lock ɾ ش. + ׷ ̷ ؾ Ȳ ü . ϴ + Dead Lock ¿ . + + 2008-04-09 21:01:00 + + ////////////////////////////////////////////////////////////////*/ + + template class ZtCAutoKeyRev + { + private: + TAutoKey& mr_CAutoKey; + public : + + ZtCAutoKeyRev(TAutoKey& AR_CAutoKey):mr_CAutoKey(AR_CAutoKey) + { + mr_CAutoKey.mr_SyncEasy.UnLock(); + }/* + ZtCAutoKeyRev(TAutoKey& AR_CAutoKey)*/ + + ~ZtCAutoKeyRev() + { + mr_CAutoKey.mr_SyncEasy.Lock(); + }/* + ~ZtCAutoKeyRev()*/ + + public: + };/* + template class ZtCAutoKeyRev */ + + + /*//////////////////////////////////////////////////// + + http://blog.naver.com/kimsk99?Redirect=Log&logNo=50004383787 + + α׷ ϸ鼭 带 , CreateThread _beginthread Լ ,  Լ ؾ ϰ ȴ. + ׻ ⺻ API CreateThread Ծ. ׷ å дٰ װ ߸Ǿٴ ˾Ҵ. MSDN + ڼ о ̾ ڼ ׵ . ϴ CreateThread SDK ϴ ⺻ API + ̴. Ư ̺귯 ũ ʾƵ ϵǰ ư. _beginthread(Ǵ _beginthreadex) standard C + library Լ ũؾ Ѵ. ׷ ɿ ̰ . ɿ ̰ ʴ´ٸ ̷ + ̴. _beginthread ޶ ʿ 찡 ִ. ׷ + Լ _beginthreadex CreateThread ڸ ִ. ׷ CreateThread _beginthreadex + ġȯ ϴ. + + εۿ ū _beginthread standard C library ϴ TLB ʱȭ شٴ ̴. standary C + library ִ Լ Ϻδ thread-safty ؼ TLB ϴµ ʱȭ ʴ´ٸ ߻ ִ. + + _beginthreadex Լ ؼ 带 ߴٸ Լ 带 ϱ ؼ ExitThread Լ ϱ ٴ + _endthreadex Լ ϱ Ѵ. + + κ C library ϱ _beginthreadex ؾ Ѵ. + + uintptr_t _beginthreadex + ( + void *security, + unsigned stack_size, + unsigned ( *start_address )( void * ), + void *arglist, + unsigned initflag, + unsigned *thrdaddr + ); + + -- + + ////////////////////////////////////////////////////*/ + + + ////////////////////////////////////////////////////// + + ///////////////// Ŭ ///////////////// + + ////////////////////////////////////////////////////// + + + + /*//////////////////////////////////////////////////// + + uintptr_t _beginthreadex + ( + void *security, + unsigned stack_size, + unsigned ( __stdcall *start_address )( void * ), + void *arglist, + unsigned initflag, + unsigned *thrdaddr + ); + + HANDLE CreateThread + ( + LPSECURITY_ATTRIBUTES lpThreadAttributes, + SIZE_T dwStackSize, + LPTHREAD_START_ROUTINE AP_StartAddress, + LPVOID lpParameter, + DWORD dwCreationFlags, + LPDWORD lpThreadId + ); + + CreateThread _beginthreadex ü ְ ׷ Ѵ. + + dwCreationFlags + [in] Flags that control the creation of the thread. + If the CREATE_SUSPENDED flag is specified, + the thread is created in a suspended state, + and will not run until the ResumeThread function is called. + If this value is zero, + the thread runs immediately after creation. + If the STACK_SIZE_PARAM_IS_A_RESERVATION flag is specified, + the dwStackSize parameter specifies the initial reserve size of the stack. + Otherwise, dwStackSize specifies the commit size. + + Windows 2000/NT and Windows Me/98/95: + The STACK_SIZE_PARAM_IS_A_RESERVATION flag is not supported. + lpThreadId + [out] Pointer to a variable that receives the thread identifier. + If this parameter is NULL, the thread identifier is not returned. + + Windows Me/98/95: This parameter may not be NULL. + + cf) DWORD ResumeThread( HANDLE hThread ); + + + **** IN WINBASE.H **** + + typedef DWORD (WINAPI *PTHREAD_START_ROUTINE) + ( + LPVOID lpThreadParameter + ); + + typedef struct _SECURITY_ATTRIBUTES + { + DWORD nLength; + LPVOID lpSecurityDescriptor; + BOOL bInheritHandle; + } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; + + typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; + + LPTHREAD_START_ROUTINE AP_StartAddress Լ + DWORD WINAPI ThreadFunc(LPVOID lpRarameter) + + + ********** MFC ȭ object ********** + + Ʒ object ؼ ʿ + + 1) CCriticalSection cs; + cs.Lock(); + // ۾ڵ + cs.Unlock(); + + 2) CEvent event; + Thread ֵ Ǵ + CEvent object ϰ Thread CallBack Լ + + UINT ThreadFunc(LPVOID pParam) + { + while(TRUE) + { + CEventOvj.Lock(); // ̵. + + // ̺Ʈ ߻ ڵ带 ´. + // ׸ ܺο + // CEventOvj.PulseEvent(); ̳ + // CEventOvj.SetEvent(); ȣϸ . + + // Thread Lock ɷ ¿ + // PulseEvent Լ ȣϸ ƹϵ Ͼ ʰ + // ٷ Lock() ȣϸ ٽ ܴ. + // SetEvent() 쿡 ׳ Ѵ. + } + //while(TRUE) + } + //UINT ThreadFunc(LPVOID pParam) + + + # Window Thread Callback Type; + + DWORD WINAPI ThreadFunc(LPVOID lpParameter); + + cf) typedef unsigned long DWORD; + + # Linux Thread Callback Type: + + void* ThreadFunc()(void*) + + + ////////////////////////////////////////////////////*/ + + + typedef DWORD ThreadReturnType ; + typedef HANDLE ThreadID ; + + + /*/////////////////////////////////////////////////////////////////// + + typedef struct _SECURITY_ATTRIBUTES { + DWORD nLength; + LPVOID lpSecurityDescriptor; + BOOL bInheritHandle; + } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; + + ///////////////////////////////////////////////////////////////////*/ + + + #define _THREAD_RETURN_ unsigned __stdcall + + + namespace ZNsIFace + { + class ZCThread_BASE{}; + }/* + namespace ZNsIFace*/ + + + template< typename TTypeBase=ZNsIFace::ZCThread_BASE + > + class ZtCThread : public TTypeBase /////////////////// + { + protected: + ThreadID mh_ThreadID; + public : + + ZtCThread() + { + _DEBUG_REENTRANT_CHECK_ + + mh_ThreadID = INVALID_HANDLE_VALUE ; + }/* + ZtCThread()*/ + + ZtCThread(TTypeBase& AR_CBaseType):TTypeBase(AR_CBaseType) + { + _DEBUG_REENTRANT_CHECK_ + }/* + ZtCThread(TTypeBase& AR_CBaseType):TTypeBase(AR_CBaseType)*/ + + ZtCThread(const ZtCThread& rhs):TTypeBase(rhs) + { + _DEBUG_REENTRANT_CHECK_ + + mh_ThreadID =rhs.mh_ThreadID ; + (TTypeBase&)(*this)=static_cast(rhs); + }/* + ZtCThread(TTypeBase& AR_CBaseType):TTypeBase(AR_CBaseType)*/ + + template + ZtCThread(const TTypeArg& AR_TTypeArg):TTypeBase(AR_TTypeArg) + { + _DEBUG_REENTRANT_CHECK_ + }/* + template + ZtCThread(const TTypeArg& AR_TTypeArg):TTypeBase(AR_TTypeArg) */ + + ZtCThread& operator=(const ZtCThread& rhs) + { + return *this; // nothing to do + }/* + ZtCThread& operator=(const ZtCThread& rhs)*/ + + + operator ThreadID () const + { + return mh_ThreadID; + }/* + operator ThreadID () const*/ + + ThreadID GetThreadID() const + { + return mh_ThreadID; + }/* + ThreadID GetThreadID() const*/ + + + /*/////////////////////////////////////////////////// + + typedef DWORD (WINAPI *PTHREAD_START_ROUTINE) + ( + LPVOID lpThreadParameter + ); + typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; + + ///////////////////////////////////////////////////*/ + + bool Make(LPTHREAD_START_ROUTINE AP_StartAddress, void* AP_Arg=0, DWORD dwCreationFlags=0, DWORD dwStackSize=0, LPSECURITY_ATTRIBUTES lpThreadAttributes=NULL) + { + unsigned int VUI_ThreadID; + + return ( mh_ThreadID = (void*)::/*CreateThread*/_beginthreadex + ( + lpThreadAttributes + , dwStackSize + , (unsigned int (__stdcall *)(void *))AP_StartAddress + , AP_Arg + , dwCreationFlags + , &VUI_ThreadID + ) + /*****/ )!=INVALID_HANDLE_VALUE ; ////////////////////////////////// + + + #if 0 // CreateThread() Լ + + DWORD VUI_ThreadID; + + return ( mh_ThreadID=::CreateThread + ( + lpThreadAttributes, + dwStackSize, + AP_StartAddress, + AP_Arg, + dwCreationFlags, + &VUI_ThreadID + ) + /*****/ )!=INVALID_HANDLE_VALUE ; + + #endif + }/* + bool Make(LPTHREAD_START_ROUTINE AP_StartAddress, void* AP_Arg=0, DWORD dwCreationFlags=0, DWORD dwStackSize=0, LPSECURITY_ATTRIBUTES lpThreadAttributes=NULL)*/ + + bool Make(unsigned (__stdcall *AP_StartAddress)(void *), void* AP_Arg=0, DWORD dwCreationFlags=0, DWORD dwStackSize=0, LPSECURITY_ATTRIBUTES lpThreadAttributes=NULL) + { + unsigned int VUI_ThreadID; + + return ( mh_ThreadID=(void*)::_beginthreadex + ( + lpThreadAttributes , + dwStackSize , + AP_StartAddress , + AP_Arg , + dwCreationFlags , + &VUI_ThreadID + ) + /*****/ )!=INVALID_HANDLE_VALUE ; ///////////// + }/* + bool Make(unsigned (__stdcall AP_StartAddress*)(void *), void* AP_Arg=0, DWORD dwCreationFlags=0, DWORD dwStackSize=0, LPSECURITY_ATTRIBUTES lpThreadAttributes=NULL)*/ + + + // ñ Լ ()Ų. + + int Wait(DWORD ADW_MilliSeconds=INFINITE) + { + return ::WaitForSingleObject(mh_ThreadID, ADW_MilliSeconds); + + /* WaitForSingleObject(HANDLE,DWORD ADW_MilliSeconds); 3 ȯ ´. + + WAIT_OBJECT_0 : HANDLE object ȣ° Ǿ. + WAIT_TIMEOUT : ŸӾƿð Ͽ. + WAIT_ABANDONED : ؽ */ + }/* + int Wait(DWORD ADW_MilliSeconds=INFINITE)*/ + + static int Wait(ThreadID AI_ThreadIDVar, DWORD ADW_MilliSeconds=INFINITE) + { + return ::WaitForSingleObject(AI_ThreadIDVar, ADW_MilliSeconds); + + /* WaitForSingleObject(HANDLE,DWORD ADW_MilliSeconds); 3 ȯ ´. + + WAIT_OBJECT_0 : HANDLE object ȣ° Ǿ. + WAIT_TIMEOUT : ŸӾƿð Ͽ. + WAIT_ABANDONED : ؽ */ + }/* + static int Wait(ThreadID AI_ThreadIDVar, DWORD ADW_MilliSeconds=INFINITE)*/ + + bool Terminate(DWORD AI_ExitCode=0) + { + return ::TerminateThread(mh_ThreadID, AI_ExitCode)==TRUE; + }/* + bool Terminate(DWORD AI_ExitCode=0)*/ + + /*//////////////////////////////////////////////////////// + + BOOL GetExitCodeThread( + HANDLE hThread, + LPDWORD lpExitCode + ); + + Parameters + + hThread + [in] Handle to the thread. + lpExitCode + [out] Pointer to a 32-bit variable to receive the thread termination status. + + Return Values + + Nonzero indicates success. + Zero indicates failure. + To get extended error information, call GetLastError. + + Remarks + + If the specified thread has not terminated, + the termination status returned is STILL_ACTIVE. + + The following termination statuses can be returned if the process has terminated: + + The exit value specified in the ExitThread or TerminateThread function + The return value from the thread function + The exit value of the thread's process + + ////////////////////////////////////////////////////////*/ + + BOOL GetExitCode(DWORD& ARRDW_ExitCode) + { + return ::GetExitCodeThread(mh_ThreadID, &ARRDW_ExitCode); + }/* + BOOL GetExitCode(DWORD& ARRDW_ExitCode)*/ + + + /*////////////////////////////////////////////////////////////// + + SuspendThread Լ Ű + ResumeThread Լ 带 ۽Ų. + + ī͸ ϴµ īƮ + SuspendThread Լ ȣǸ ϰ ResumeThread Լ ȣ + Ǹ ϸ īƮ 0 ̸ 簳ȴ. ׷ + SuspendThread Լ ι ȣߴٸ ResumeThread Լ ι + ȣ ־ 尡 簳ȴ. + + ׷ٸ ResumeThread ȣϰ SuspendThread ߿ + ȣϸ  ɱ. 쿡 ȴ. īƮ -1 + 0 Ǿ īƮ + 0 ̸δ ʴ . + + POSIX ǥؾȿ ̷ Լ µ, POSIX 带 + α׷ (ȭ, David R. Butenhof) 301 Page + suspend resume ִ. + + ֶ󸮽 thr_suspend(), thr_continue() Լ Ѵ. + + -- + + //////////////////////////////////////////////////////////////*/ + + DWORD Suspend() + { + return ::SuspendThread(mh_ThreadID); + }/* + DWORD Suspend()*/ + + DWORD Resume() + { + return ::ResumeThread(mh_ThreadID); + }/* + DWORD Resume()*/ + + bool Close() + { + return ::CloseHandle(mh_ThreadID)==TRUE; + }/* + bool Close()*/ + + bool Detach() // for compatibility with linux + { + return true; + }/* + bool Detach()*/ + + public: + };/* + template< typename TTypeBase=ZNsIFace::ZCThread_BASE + >/ + class ZtCThread ////////////////////////////////////*/ + + + template<> class ZtCThread + { + protected: + ThreadID mh_ThreadID; + public : + + ZtCThread() + { + _DEBUG_REENTRANT_CHECK_ + + mh_ThreadID = INVALID_HANDLE_VALUE ; + }/* + ZtCThread()*/ + + ZtCThread(const ZtCThread& rhs) + { + mh_ThreadID=rhs.mh_ThreadID; + }/* + ZtCThread(const ZtCThread& rhs)*/ + + ZtCThread& operator=(const ZtCThread& rhs) + { + return *this; + }/* + ZtCThread& operator=(const ZtCThread& rhs)*/ + + operator ThreadID () const + { + return mh_ThreadID; + }/* + operator ThreadID () const*/ + + ThreadID GetThreadID() const + { + return mh_ThreadID; + }/* + ThreadID GetThreadID() const*/ + + bool Make(LPTHREAD_START_ROUTINE AP_StartAddress, void* AP_Arg=0, DWORD dwCreationFlags=0, DWORD dwStackSize=0, LPSECURITY_ATTRIBUTES lpThreadAttributes=NULL) + { + unsigned int VUI_ThreadID; + + return ( mh_ThreadID = (void*)::_beginthreadex + ( + lpThreadAttributes, + dwStackSize, + (unsigned int (__stdcall *)(void *))AP_StartAddress, + AP_Arg, + dwCreationFlags, + &VUI_ThreadID + ) + /*****/ )!=INVALID_HANDLE_VALUE ; /////////////// + + + #if 0 // CreateThread() Լ + + DWORD VUI_ThreadID; + + return ( mh_ThreadID = ::CreateThread + ( + lpThreadAttributes, + dwStackSize, + AP_StartAddress, + AP_Arg, + dwCreationFlags, + &VUI_ThreadID + ) + /*****/ )!=INVALID_HANDLE_VALUE ; + + #endif + }/* + bool Make(LPTHREAD_START_ROUTINE AP_StartAddress, void* AP_Arg=0, DWORD dwCreationFlags=0, DWORD dwStackSize=0, LPSECURITY_ATTRIBUTES lpThreadAttributes=NULL)*/ + + bool Make(unsigned (__stdcall *AP_StartAddress)(void *), void* AP_Arg=0, DWORD dwCreationFlags=0, DWORD dwStackSize=0, LPSECURITY_ATTRIBUTES lpThreadAttributes=NULL) + { + unsigned int VUI_ThreadID; + + return ( mh_ThreadID=(void*)::_beginthreadex + ( + lpThreadAttributes , + dwStackSize , + AP_StartAddress , + AP_Arg , + dwCreationFlags , + &VUI_ThreadID + ) + /*****/ )!=INVALID_HANDLE_VALUE ; ///////////// + }/* + bool Make(unsigned (__stdcall AP_StartAddress*)(void *), void* AP_Arg=0, DWORD dwCreationFlags=0, DWORD dwStackSize=0, LPSECURITY_ATTRIBUTES lpThreadAttributes=NULL)*/ + + int Wait(DWORD ADW_MilliSeconds=INFINITE) + { + return ::WaitForSingleObject(mh_ThreadID, ADW_MilliSeconds); + }/* + int Wait(DWORD ADW_MilliSeconds=INFINITE)*/ + + static int Wait(ThreadID AI_ThreadIDVar, DWORD ADW_MilliSeconds=INFINITE) + { + return ::WaitForSingleObject(AI_ThreadIDVar, ADW_MilliSeconds); + }/* + static int Wait(ThreadID AI_ThreadIDVar, DWORD ADW_MilliSeconds=INFINITE)*/ + + bool Terminate(DWORD AI_ExitCode=0) + { + return ::TerminateThread(mh_ThreadID, AI_ExitCode)==TRUE; + }/* + bool Terminate(DWORD AI_ExitCode=0)*/ + + BOOL GetExitCode(DWORD& ARRDW_ExitCode) + { + return ::GetExitCodeThread(mh_ThreadID, &ARRDW_ExitCode); + }/* + BOOL GetExitCode(DWORD& ARRDW_ExitCode)*/ + + DWORD Suspend() + { + return ::SuspendThread(mh_ThreadID); + }/* + DWORD Suspend()*/ + + DWORD Resume() + { + return ::ResumeThread(mh_ThreadID); + }/* + DWORD Resume()*/ + + bool Close() + { + return ::CloseHandle(mh_ThreadID)==TRUE; + }/* + bool Close()*/ + + bool Detach() // for compatibility with linux + { + return true; + }/* + bool Detach()*/ + + public: + };/* + template<> class ZtCThread*/ + + + + /*/////////////////////////////////////////////////////////////////////////////// + + + ȣ : 㰡ϴ + + ڵ ̺Ʈ : ° Ǹ ڵ ȣ ° ȴ. + ̺Ʈ : 尡 ȣ · ȣ¸ Ѵ. + + SetEvent ̺Ʈ ȣ· , + ResetEvent ̺Ʈ ȣ· . + ( ٸ 尡 · .) + + ڵ ̺Ʈ 尡 WaitForSingleObject() ȣϸ ٸ + SetEvent() Լ ̺Ʈ ȣ · Ȥ ðŭ + ȴ. + + ̺Ʈ ټ 尡  ٸٰ Ǿ + ϰ ϴ ִµ ǵ/ lock ̳ ؽ + ִ. ε ִ. ټ 尡 +  ϰ ִٰ  Ǹ īƮ + ŭ ÷ָ 尡  ̴. + +  ϴ , ( ׽Ʈغ ʾ) Window + īƮ ϴ ŭ ÷־ 尡 + ѹ  ʾҴ. īƮ 1 Ű ڵ带 + ŭ ־ Ѵ. + + 2008-05-05 15:38:00 + + ///////////////////////////////////////////////////////////////////////////////*/ + + + template class ZtCEvent : public TData + { + protected: + ZTypeID mh_TypeID; + public : + + /*////////////////////////////////////////////////////////////////////////////// + + CreateEvent() + + A handle to the event object indicates success. + If the named event object existed before the function call, + the function returns a handle to the existing object and + GetLastError returns ERROR_ALREADY_EXISTS. + NULL indicates failure. To get extended error information, call GetLastError. + + //////////////////////////////////////////////////////////////////////////////*/ + + bool Make(LPCTSTR AP_Name, BOOL AB_Reset=TRUE, BOOL AB_ManualReset=TRUE, LPSECURITY_ATTRIBUTES AP_SecAtt=NULL) + { + return (mh_TypeID = ::CreateEvent(AP_SecAtt, AB_Reset, AB_ManualReset, AP_Name))!=NULL; + }/* + bool Make(LPCTSTR AP_Name, BOOL AB_Reset=TRUE, BOOL AB_ManualReset=TRUE, LPSECURITY_ATTRIBUTES AP_SecAtt=NULL)*/ + + bool Set() const // ̺Ʈ ȣ· . + { + return ::SetEvent(mh_TypeID)==TRUE; + }/* + bool Set() const*/ + + bool Reset() const // ̺Ʈ ȣ· . + { + return ::ResetEvent(mh_TypeID)==TRUE; + }/* + bool Reset()*/ + + bool Pulse() const + { + return ::PulseEvent(mh_TypeID)==TRUE; + + /*////////////////////////////////////////////////////////////////////////////////////////////////////// + + ̺Ʈ SetEvent() Լ ȣϿ ̺Ʈ ȣ · . ׸ ϴ 尡 + ¸  ٽ ڵ ̺Ʈ ȣ · ش. ׷ϱ ̺Ʈ + ڵ ̺Ʈ ȿ ִ Լ̴. ׷ MSDN Ҿϱ + ִ. + + http://msdn.microsoft.com/en-us/library/ms684914(VS.85).aspx + + Sets the specified event object to the signaled state and then resets it to the nonsignaled state + after releasing the appropriate number of waiting threads. + + Note : This function is unreliable and should not be used. + It exists mainly for backward compatibility. For more information, see Remarks. + + ϱ⸦ + + " ̺Ʈ ڵ ̺Ʈ ȿ ִ Լ̴." + + ߴµ ̰ Ʋ. ̺Ʈ ȣ · , ̺Ʈ ϴ 尡  + Ȯ Ŀ ̺Ʈ ٽ ȣ · . ̺Ʈ ȣ · , + Ʈ ϴ 尡  Ⱓ ؾ Ѵ. Ƹ κ ó Ҿ + ϱ MSDN "unreliable" ̶ ̴. + + -- 2009-02-05 0:10:00 + + //////////////////////////////////////////////////////////////////////////////////////////////////////*/ + }/* + bool Pulse() const*/ + + int Wait(DWORD ADW_MilliSeconds=INFINITE) const + { + return ::WaitForSingleObject(mh_TypeID, ADW_MilliSeconds); + }/* + int Wait(DWORD ADW_MilliSeconds=INFINITE) const*/ + + + /*////////////////////////////////////////////////////////////////////////////////////// + + ::WaitForSingleObject() ȯ + + WAIT_OBJECT_0 : The state of the specified object is signaled. + WAIT_TIMEOUT : The time-out interval elapsed, and the object's state is nonsignaled. + WAIT_FAILED : Fail + + Ʒ Lock 迭 Լ ƴϸ ZEThread_OK ZEThread_TimeOut ȯ ִ. + + //////////////////////////////////////////////////////////////////////////////////////*/ + + int Lock() const + { + return ::WaitForSingleObject(mh_TypeID, INFINITE); + }/* + int Lock() const*/ + + int LockRaw(DWORD ADW_MilliSeconds=INFINITE) const + { + return ::WaitForSingleObject(mh_TypeID, ADW_MilliSeconds); + }/* + int LockRaw(DWORD ADW_MilliSeconds=INFINITE) const*/ + + int LockTime(DWORD AI_TimeOutMili) + { + return LockRaw(AI_TimeOutMili); + }/* + int LockTime(DWORD AI_TimeOutMili)*/ + + bool UnLock() const // ̺Ʈ ȣ· . + { + return this->Set(); + }/* + bool UnLock()*/ + + public: + };/* + template class ZtCEvent */ + + + template class ZtCBarrier : public TData + { + protected: + ZTypeID mh_EventID; volatile + LONG ml_BarrCnt; + public : + + ZtCBarrier() + { + mh_EventID=0; + ml_BarrCnt=0; + }/* + ZtCBarrier()*/ + + bool IsValid() const{return mh_EventID != 0 ; } + + + /*///////////////////////////////////////////////////////////////////////////// + + Init() Fini() ȯ linux ȣȯ bool ƴϰ int ̴. + ȯ ٷ + + if(CBarrierObj.Init(3)==ZNsEnum::ZEBarrier_OK) + + ̷ . + + Init() Լ ȣ ̺Ʈ . + + /////////////////////////////////////////////////////////////////////////////*/ + + int Init(unsigned AI_Count, LPSECURITY_ATTRIBUTES AP_SemaphoreAttributes=NULL, LPCTSTR AP_EventName=NULL) + { + if(AI_Count<1) AI_Count=1; ml_BarrCnt=AI_Count; + + /*//////////////////////////////////////////////////// + + ::CreateEvent() 3 μ : bInitialState + + If this parameter is TRUE, + the initial state of the event object is signaled; + otherwise, it is nonsignaled + + ////////////////////////////////////////////////////*/ + + if(mh_EventID!=0) return ::ResetEvent(mh_EventID)==TRUE; + + return (mh_EventID=::CreateEvent( ////////////////////// + AP_SemaphoreAttributes , + TRUE /*bManualReset */ , + FALSE /*bInitialState*/ , + AP_EventName) + /*/////////*/ )!=(HANDLE)ERROR_INVALID_HANDLE ; //////// + }/* + int Init(unsigned AI_Count, LPSECURITY_ATTRIBUTES AP_SemaphoreAttributes=NULL, LPCTSTR AP_EventName=NULL)*/ + + int Fini() + { + bool VB_IsOK= + (::CloseHandle(mh_EventID)==TRUE); + + mh_EventID=0; return VB_IsOK; + }/* + int Fini()*/ + + bool Wait() + { + if(::InterlockedDecrement(&ml_BarrCnt)>0) + { + return ::WaitForSingleObject(mh_EventID, INFINITE) != WAIT_FAILED; + }/* + if(::InterlockedDecrement(&ml_BarrCnt)>0)*/ + + return ::SetEvent(mh_EventID)==TRUE ; + }/* + bool Wait()*/ + + + /*//////////////////////////////////////////////////////////////////////////////// + + + LONG __cdecl InterlockedDecrement(__inout LONG volatile *Addend); + + Parameters : Addend [in, out] : A pointer to the variable to be decremented. + Return Value : The function returns the resulting decremented value. + + The variable pointed to by the Addend parameter must be aligned on a 32-bit boundary; + otherwise, this function will behave unpredictably on multiprocessor x86 systems and any non-x86 systems. + See _aligned_malloc. + + The interlocked functions provide a simple mechanism for synchronizing access to a variable + that is shared by multiple threads. + This function is atomic with respect to calls to other interlocked functions. + + This function is implemented using a compiler intrinsic where possible. + For more information, see the Winbase.h header file and _InterlockedDecrement. + + This function generates a full memory barrier (or fence) to ensure + that memory operations are completed in order. + + Provides compiler intrinsic support for the Win32 Platform SDK InterlockedDecrement function. + + long _InterlockedDecrement( + long * lpAddend + ); + long _InterlockedDecrement_acq( + long * lpAddend + ); + long _InterlockedDecrement_acq( + long * lpAddend + ); + short _InterlockedDecrement16( + short * lpAddend + ); + short _InterlockedDecrement16_acq( + short * lpAddend + ); + short _InterlockedDecrement16_rel( + short * lpAddend + ); + __int64 _InterlockedDecrement64( + __int64 * lpAddend + ); + __int64 _InterlockedDecrement64_acq( + __int64 * lpAddend + ); + __int64 _InterlockedDecrement64_rel( + __int64 * lpAddend + ); + + + Parameters + + [in, out] lpAddend + Pointer to the variable to be decremented. + + Return Value + + Windows 98, Windows NT 4.0, and later: + The return value is the resulting decremented value. + + Windows 95, Windows NT 3.51, and earlier: + If the result of the operation is zero, the return value is zero. + If the result of the operation is less than zero, the return value is negative, + but it is not necessarily equal to the result. + If the result of the operation is greater than zero, + the return value is positive, but it is not necessarily equal to the result. + + MSDN Ǵϸ InterlockedDecrement Լ + _InterlockedDecrement~ 迭 SDK ϴµ ̵ SDK + ' ҵ ȯ ʴ´' ִ. ̰ Լ + + LONG __cdecl InterlockedIncrement(__inout LONG volatile *Addend); + + ؼ ̴. + + ////////////////////////////////////////////////////////////////////////////////*/ + + public: + };/* + template< typename TData=ZNsMain::ZCEmpty + > + class ZtCBarrier ////////////////////////*/ + + + /*/////////////////////////////////////////////////////////////////// + + ̿ؼ Ȱ ִ barrier Ŭ ø + + ZtCBarrier<> ټ ̴. + + event 2 Ѵ. ϳ Դ̰ ϳ + 尡 Ǯ⸦ Ȯϴµ Ѵ. + + ׽Ʈ ̻ϰ lock ɸ ִ. ȭ ɶ + . + + -- 2009-01-22 23:06:00 + + ///////////////////////////////////////////////////////////////////*/ + + template< typename TSyncExec=ZNsMain::ZCCriticSectEasy, + typename TData =ZNsMain::ZCEmpty + > + class ZtCCondBarrier : public TData ///////////////////// + { + public : + typedef ZNsMain::ZtCAutoKey CAutoKey; + public : + + enum EStep + { + EStep_None, + EStep_Init, + EStep_Wait, + EStep_Dead, + EStep_Fini + };/* + enum EStep*/ + + /*public :*/ + protected: + TSyncExec mo_CSyncExec; + ZTypeID mh_EventID ; + ZTypeID mh_EWaitID ; // ϴ ̺Ʈ + int mi_BarrCnt ; + int mi_WaitCnt ; + EStep me_EStep ; + public : + + ZtCCondBarrier( LPCTSTR AP_EventName =NULL, + LPCTSTR AP_EventName2=NULL, + LPSECURITY_ATTRIBUTES AP_SemaphoreAttributes =NULL, + LPSECURITY_ATTRIBUTES AP_SemaphoreAttributes2=NULL + /*/////////*/ ) + { + me_EStep =EStep_None; + mi_BarrCnt=0 ; + mi_WaitCnt=0 ; + + mh_EventID=::CreateEvent( //////////////////// + AP_SemaphoreAttributes , + TRUE /*bManualReset*/ , + FALSE /*bInitialState*/, + AP_EventName + /*/////////*/ ); ///////////////////////////// + + mh_EWaitID=::CreateEvent( //////////////////// + AP_SemaphoreAttributes2 , + TRUE /*bManualReset*/ , + FALSE /*bInitialState*/ , + AP_EventName2 + /*/////////*/ ); ///////////////////////////// + }/* + ZtCCondBarrier( LPCTSTR AP_EventName =NULL, + LPCTSTR AP_EventName2=NULL, + LPSECURITY_ATTRIBUTES AP_SemaphoreAttributes =NULL, + LPSECURITY_ATTRIBUTES AP_SemaphoreAttributes2=NULL + ///////////// ) */ + + + ~ZtCCondBarrier() + { + ::CloseHandle(mh_EventID); + ::CloseHandle(mh_EWaitID); + }/* + ~ZtCCondBarrier()*/ + + EStep GetStep() const + { + return me_EStep; + }/* + EStep GetStep() const*/ + + bool IsValidID() const + { + return mh_EventID!=(HANDLE)ERROR_INVALID_HANDLE; + }/* + bool IsValidID() const*/ + + int Init(int AI_Count) + { + CAutoKey VO_CAutoKey(mo_CSyncExec); + + if(me_EStep!=EStep_None && me_EStep!=EStep_Fini) + return ZNsEnum::ZEBarrier_NO; + //endif + + if(AI_Count<1) AI_Count=1; + + mi_BarrCnt=AI_Count ; + mi_WaitCnt=AI_Count ; + me_EStep =EStep_Init; + + return ZNsEnum::ZEBarrier_OK; + }/* + int Init(int AI_Count)*/ + + bool Wait() + { + mo_CSyncExec.Lock(); + + if(me_EStep==EStep_Init) + { + me_EStep=EStep_Wait; + } + if(me_EStep!=EStep_Wait) + { + mo_CSyncExec.UnLock(); return false; + }/* + if(me_EStep!=EStep_Wait)*/ + + bool VB_IsOK=false; + + if(--mi_BarrCnt>0) + { + #ifdef _DEBUG + cout<<" Wait Barrier : mi_BarrCnt="< Project -> Settings -> c/c++ -> Category -> + Code Generation -> Use run-time library -> + Ƽ ̺귯 Ͽ + Ǵ, ɼǿ /MT, /MD, /MTd, /MDd ߿ ϳ Ѵ. + /MT ũ + /MD ũ + /MTd ũ(DEBUG ) + /MDd ũ(DEBUG ) + -- + +////////////////////////////////////////////////////////////////////////////*/ + + +#endif //__ZCPPMAIN__PROCESS_WIN_H__ diff --git a/ZCppMain/ZCStringStd.H b/ZCppMain/ZCStringStd.H index 7d49408..74da319 100644 --- a/ZCppMain/ZCStringStd.H +++ b/ZCppMain/ZCStringStd.H @@ -113,7 +113,7 @@ namespace ZNsMain TypeLength VL_NeedSize = VL_ThisSize + (AL_Replace-AL_Searched) * VL_PosListSize ; - TypePChar VPC_ThisStart = this->data() ; + TypePChar VPC_ThisStart = const_cast(this->data()) ; IterEasyID VH_IterEasyID = AR_CPosList.ItHID(); TypeLength VL_SearchedPos= 0 ; TypeLength VL_SearchedPre= 0 ; // VL_SearchedPos 의 이전 값 @@ -179,7 +179,7 @@ namespace ZNsMain ARR_SaveOut.resize(VL_NeedSize); - TypePChar VPC_OutStart = ARR_SaveOut.data() ; + TypePChar VPC_OutStart = const_cast(ARR_SaveOut.data()) ; TypePChar VPC_CopyStart = 0 ; TypePChar VPC_DestStart = 0 ; TypeLength VL_CopyStart = 0 ; diff --git a/ZCppMain/ZMainHead.H b/ZCppMain/ZMainHead.H index 3b38aa7..33e2707 100644 --- a/ZCppMain/ZMainHead.H +++ b/ZCppMain/ZMainHead.H @@ -2671,15 +2671,15 @@ namespace ZNsMain template< typename TType, typename TypeArg=const TType& > - class ZtCExceptBase_T /*///////////////////////////////*/ + class ZtCExceptBase /*/////////////////////////////////*/ { protected: TType mo_Type; public : - ZtCExceptBase_T(){} + ZtCExceptBase(){} - ZtCExceptBase_T(TypeArg TypeArgObj):mo_Type(TypeArgObj){} + ZtCExceptBase(TypeArg TypeArgObj):mo_Type(TypeArgObj){} TType& operator()(){return mo_Type;} @@ -2687,7 +2687,7 @@ namespace ZNsMain };/* template< typename TType, typename TypeArg=const TType& > - class ZtCExceptBase_T /////////////////////////////////*/ + class ZtCExceptBase ///////////////////////////////////*/ /*///////////////////////////////////////////////////////////////////////////////// @@ -2705,16 +2705,16 @@ namespace ZNsMain /////////////////////////////////////////////////////////////////////////////////*/ - class CNonCopyable + class ZCNonCopyable { private: - CNonCopyable(const CNonCopyable& rhs){} - CNonCopyable& operator=(const CNonCopyable& rhs){return *this;} + ZCNonCopyable(const ZCNonCopyable& rhs){} + ZCNonCopyable& operator=(const ZCNonCopyable& rhs){return *this;} public : - CNonCopyable(){} + ZCNonCopyable(){} public : };/* - class CNonCopyable*/ + class ZCNonCopyable*/ /*/////////////////////////////////////////////////////////////////////////// diff --git a/ZCppMain/ZMainHeadEx.H b/ZCppMain/ZMainHeadEx.H index ec6a0fc..2247a84 100644 --- a/ZCppMain/ZMainHeadEx.H +++ b/ZCppMain/ZMainHeadEx.H @@ -1713,7 +1713,10 @@ namespace ZNsMain ZCStdTime(const ZCStdTime& rhs) { - if(this==&rhs) return; + if(this==&rhs) + { + mb_IsLocal = true; return; + } mb_IsLocal =rhs.mb_IsLocal ; mo_FILETIME =rhs.mo_FILETIME ; diff --git a/ZCppMain/ZtCSimList.H b/ZCppMain/ZtCSimList.H index ee85501..2d5427c 100644 --- a/ZCppMain/ZtCSimList.H +++ b/ZCppMain/ZtCSimList.H @@ -234,7 +234,7 @@ namespace ZNsMain public: #ifdef _REENTRANT_MUTEX - ZNsMain::CMutexSmallInit mo_Mutex ; + ZNsMain::ZCMutexSmallInit mo_Mutex ; #endif //_REENTRANT_MUTEX private: @@ -253,7 +253,7 @@ namespace ZNsMain ZCLink* GetOneLink() { #ifdef _REENTRANT_MUTEX - ZNsMain::CMutexSmallLock VO_CMutexSmallLock(mo_Mutex); + ZNsMain::ZCMutexSmallLock VO_ZCMutexSmallLock(mo_Mutex); #endif //_REENTRANT_MUTEX #ifdef _DEBUG @@ -288,7 +288,7 @@ namespace ZNsMain /*************/ ) { #ifdef _REENTRANT_MUTEX - ZNsMain::CMutexSmallLock VO_CMutexSmallLock(mo_Mutex); + ZNsMain::ZCMutexSmallLock VO_ZCMutexSmallLock(mo_Mutex); #endif //_REENTRANT_MUTEX #ifdef _DEBUG @@ -397,7 +397,7 @@ namespace ZNsMain // 기존에 있는 ml_UseSize 개의 링크를 먼저 사용한다. #ifdef _REENTRANT_MUTEX - ZNsMain::CMutexSmallLock VO_CMutexSmallLock(mo_Mutex); + ZNsMain::ZCMutexSmallLock VO_ZCMutexSmallLock(mo_Mutex); #endif //_REENTRANT_MUTEX #ifdef _DEBUG @@ -479,7 +479,7 @@ namespace ZNsMain /**********/ ) { #ifdef _REENTRANT_MUTEX - ZNsMain::CMutexSmallLock VO_CMutexSmallLock(mo_Mutex); + ZNsMain::ZCMutexSmallLock VO_ZCMutexSmallLock(mo_Mutex); #endif //_REENTRANT_MUTEX #ifdef _DEBUG @@ -577,7 +577,7 @@ namespace ZNsMain #ifdef _REENTRANT_MUTEX - ZNsMain::CMutexSmallLock VO_CMutexSmallLock(mo_Mutex); + ZNsMain::ZCMutexSmallLock VO_ZCMutexSmallLock(mo_Mutex); #endif //_REENTRANT_MUTEX #ifdef _DEBUG @@ -658,7 +658,7 @@ namespace ZNsMain void ReceiveLink(ZCLink* AP_Link) { #ifdef _REENTRANT_MUTEX - ZNsMain::CMutexSmallLock VO_CMutexSmallLock(mo_Mutex); + ZNsMain::ZCMutexSmallLock VO_ZCMutexSmallLock(mo_Mutex); #endif //_REENTRANT_MUTEX AP_Link->mp_NextLink=0; @@ -682,7 +682,7 @@ namespace ZNsMain void ReceiveLink(ZCLink* AP_HeadLink,ZCLink* AP_TailLink,TTypSize AL_Count) { #ifdef _REENTRANT_MUTEX - ZNsMain::CMutexSmallLock VO_CMutexSmallLock(mo_Mutex); + ZNsMain::ZCMutexSmallLock VO_ZCMutexSmallLock(mo_Mutex); #endif //_REENTRANT_MUTEX if(ml_UseSize==0) @@ -771,7 +771,7 @@ namespace ZNsMain void DeleteAllInHeap() { #ifdef _REENTRANT_MUTEX - ZNsMain::CMutexSmallLock VO_CMutexSmallLock(mo_Mutex); + ZNsMain::ZCMutexSmallLock VO_ZCMutexSmallLock(mo_Mutex); #endif //_REENTRANT_MUTEX if(ml_UseSize==0) diff --git a/ZCppMainTest/ZtCThreadEx_000.cpp b/ZCppMainTest/ZtCThreadEx_000.cpp new file mode 100644 index 0000000..f5a1d2c --- /dev/null +++ b/ZCppMainTest/ZtCThreadEx_000.cpp @@ -0,0 +1,170 @@ + + +#ifndef _REENTRANT_EX +#define _REENTRANT_EX +#endif + + +#include +#include "ZCppMain/ZCStringStd.H" +#include "ZCppMain/ZCProcess.H" + + +using namespace std ; +using namespace ZNsMain; + + +namespace ZNsMain +{ + + namespace ZNsExam + { + + template class ZtCExamThread + { + public: + + class CThreadMy : public ZNsMain::ZtCThreadEx + { + public: + + void Init(ZCStringStd& AR_KeyCStr) + { + cout<<"# Init() : "<*/ + + + static int Main(int AI_ArgCnt=0, char* APP_ArgVal[]=0) + { + CThreadMy VO_CThreadMy ; + ZCStringStd VO_ZCStringStd1("Help Data1"); + ZCStringStd VO_ZCStringStd2("Help Data2"); + + VO_CThreadMy.Make(ZftMCP(VO_ZCStringStd1)); + cout<<"# Press Enter to continue."< class ZtCExamThread*/ + + }/* + namespace ZNsExam*/ + +}/* +namespace ZNsMain*/ + + +int main(int AI_ArgCnt, char* APP_ArgVal[]) +{ + return ZNsMain::ZNsExam:: + + ZtCExamThread<>::Main(AI_ArgCnt, APP_ArgVal); +}/* +int main(int AI_ArgCnt, char* APP_ArgVal[])*/ + + +/*//////////////////////////////////////////////////////////////////////////////////////// + +■ cigwin 컴파일 + + // g++ -mno-cygwin -o ZtCThreadEx_000.exe ZtCThreadEx_000.cpp -I../../my_CPP/CPP_Main/ -I../../my_CPP/CPP_Std/ -D__CYGWIN32__ -D__VISUAL_CPP_VER__=200300 + // g++ -mno-cygwin -o ZtCThreadEx_000_D.exe ZtCThreadEx_000.cpp -I../../my_CPP/CPP_Main/ -I../../my_CPP/CPP_Std/ -D__CYGWIN32__ -D__VISUAL_CPP_VER__=200300 -D_DEBUG + +■ mingw 컴파일 + + g++.exe -o ZtCThreadEx_000_mw.exe ZtCThreadEx_000.cpp -I../ + g++.exe -o ZtCThreadEx_000_mw_D.exe ZtCThreadEx_000.cpp -I../ -D_DEBUG + + ./ZtCThreadEx_000_mw.exe + ./ZtCThreadEx_000_mw_D.exe + + + Administrator@q381-2673 UCRT64 /e/my_CPP/ZCpp/ZCppMainTest + # date + Sun Aug 24 10:47:09 KST 2025 + + Administrator@q381-2673 UCRT64 /e/my_CPP/ZCpp/ZCppMainTest + # g++ --version + g++.exe (Rev2, Built by MSYS2 project) 13.2.0 + Copyright (C) 2023 Free Software Foundation, Inc. + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + +■ Linux 컴파일 + + g++ -std=c++98 -o ZtCThreadEx_000.exe ZtCThreadEx_000.cpp -I../ -lpthread + g++ -std=c++98 -o ZtCThreadEx_000_D.exe ZtCThreadEx_000.cpp -I../ -lpthread -D_DEBUG + + sauron@q381-2673:/mnt/e/my_CPP/ZCpp/ZCppMainTest$ gcc --version + gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0 + Copyright (C) 2019 Free Software Foundation, Inc. + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + sauron@q381-2673:/mnt/e/my_CPP/ZCpp/ZCppMainTest$ date + Sun Aug 24 00:05:51 DST 2025 + + sauron@q381-2673:/mnt/e/my_CPP/ZCpp/ZCppMainTest$ cat /etc/os-release + NAME="Ubuntu" + VERSION="20.04.6 LTS (Focal Fossa)" + ID=ubuntu + ID_LIKE=debian + PRETTY_NAME="Ubuntu 20.04.6 LTS" + VERSION_ID="20.04" + HOME_URL="https://www.ubuntu.com/" + SUPPORT_URL="https://help.ubuntu.com/" + BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" + PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" + VERSION_CODENAME=focal + UBUNTU_CODENAME=focal + + + [sauron@q381-2657 ZCppMainTest]$ cat /etc/centos-release + CentOS Linux release 7.9.2009 (Core) + + [sauron@q381-2657 ZCppMainTest]$ g++ --version + g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44) + Copyright (C) 2015 Free Software Foundation, Inc. + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +■ 실행 + + ./ZtCThreadEx_000.exe + ./ZtCThreadEx_000_D.exe + +////////////////////////////////////////////////////////////////////////////////////////*/