Files
RepoMain/ZCppMain/ZCProcess_Linux.H

4679 lines
160 KiB
C++
Raw Normal View History


#ifndef __ZCPPMAIN__PROCESS_LINUX_H__
#define __ZCPPMAIN__PROCESS_LINUX_H__
#include "ZCppMain/ZMainHead.H"
#include <fstream>
#include <sys/time.h>
#include <signal.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/mman.h>
#include <unistd.h>
#include <semaphore.h>
#include <fcntl.h>
#include <pthread.h>
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 .
<semaphore.h> .
<sys/sem.h> .
-- 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 은 나머지 알람 요청을 취소. 나머지 알람 호출
-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 <signal.h>
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 <sys/types.h>
#include <signal.h>
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 <sys/ipc.h>
#include <sys/shm.h>
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 <semaphore.h>
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 <semaphore.h>
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 .
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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<"Error !! ZCThreadMutexEasy() Fail To Mutex"<<std::endl;
fileout.close();
exit(1);
}/*
if(this->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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<"Error !! ZCThreadMutexEasy(const ZCThreadMutexEasy&) Fail To Mutex"<<std::endl;
fileout.close();
::exit(1);
}/*
if(this->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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<"Error !! ~ZCThreadMutexEasy() Fail To Close Mutex"<<std::endl;
fileout.close();
::exit(1);
}/*
if(this->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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<"Error !! ZCThreadMutexAttrEasy() Fail To Mutex"<<std::endl;
fileout.close();
exit(1);
}/*
if(this->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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<"Error !! ZCThreadMutexAttrEasy(const ZCThreadMutexAttrEasy&) Fail To Mutex"<<std::endl;
fileout.close();
exit(1);
}/*
if(this->ZCThreadMutexAttr::Make()==false)*/
}/*
ZCThreadMutexAttrEasy(const ZCThreadMutexAttrEasy&)*/
~ZCThreadMutexAttrEasy()
{
if(this->ZCThreadMutexAttr::Close()==false)
{
std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app);
fileout<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<"Error !! ~ZCThreadMutexAttrEasy() Fail To Close Mutex"<<std::endl;
fileout.close();
exit(1);
}/*
if(this->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<int, int>)
, g++ 7.3.0 .
CProcess_Linux.H:2429:25: warning:
dynamic exception specifications are deprecated in C++11 [-Wdeprecated]
ZCSpinLockEasy() throw(ZtCExceptBase<int, int>)
-- 2018-06-26 15:12:00
#######################################################################*/
ZCSpinLockEasy() /*throw(ZtCExceptBase<int, int>)*/
{
int VI_Return=this->Init();
if(VI_Return!=0)
{
throw ZtCExceptBase<int, int>(VI_Return);
}/*
if(VI_Return!=0)*/
}/*
ZCSpinLockEasy()*/
ZCSpinLockEasy(const ZCSpinLockEasy& rhs)
{
int VI_Return=this->Init();
if(VI_Return!=0)
{
throw ZtCExceptBase<int, int>(VI_Return);
}/*
if(VI_Return!=0)*/
}/*
ZCSpinLockEasy(const ZCSpinLockEasy& rhs)*/
void Lock()
{
int VI_Return=this->ZCSpinLock::Lock();
if(VI_Return!=0)
{
throw ZtCExceptBase<int, int>(VI_Return);
}/*
if(VI_Return!=0)*/
}/*
void Lock() throw(ZtCExceptBase<int, int>)*/
void UnLock()
{
int VI_Return=this->ZCSpinLock::UnLock();
if(VI_Return!=0)
{
throw ZtCExceptBase<int, int>(VI_Return);
}/*
if(VI_Return!=0)*/
}/*
void UnLock() throw(ZtCExceptBase<int, int>)*/
~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<typename TAutoKey> 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<typename TAutoKey> 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() "<<this<<", "<<++msi_CallCnt<<" ▶▶▶▶"<<endl;
#endif //_DEBUG_CAUTOKEY_
mr_SyncEasy.Lock();
}/*
ZtCAutoKey(TCriticSectEasy& AR_SyncEasy)*/
~ZtCAutoKey()
{
#ifdef _DEBUG_CAUTOKEY_
cout<<"◀◀◀◀ ZtCAutoKey::~ZtCAutoKey() "<<this<<", "<<--msi_CallCnt<<" ◀◀◀◀"<<endl;
#endif //_DEBUG_CAUTOKEY_
mr_SyncEasy.UnLock();
}/*
ZtCAutoKey()*/
public:
};/*
template<typename TCriticSectEasy=ZCThreadMutexEasy> class ZtCAutoKey */
#ifdef _DEBUG_CAUTOKEY_
template<typename TCriticSectEasy>
int ZtCAutoKey<TCriticSectEasy>::msi_CallCnt = 0 ;
#endif //_DEBUG_CAUTOKEY_
/*////////////////////////////////////////////////////////////////
ZtCAutoKeyRev<> ZtCAutoKey<>
Lock , Lock .
.
Dead Lock .
2008-04-09 21:01:00
////////////////////////////////////////////////////////////////*/
template<typename TAutoKey> 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<typename TAutoKey> 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 <afxmt.h>
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<typename TTypeArg>
ZtCThreadAttr(const TTypeArg& AR_TTypeArg) : TTypeBase(AR_TTypeArg)
{
}/*
template<typename TTypeArg>
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<const TTypeBase&>(rhs);
}
template<typename TTypeArg>
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<ZNsIFace::ZCThread_BASE>
{
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<ZNsIFace::ZCThread_BASE>*/
/*//////////////////////////////////////////////////////////////////////////////////////
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
.
.
.
.
( , .)
.
.
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
.
.
.
-- , ,
///////////////////////////////////////////////////////////////////////////////*/
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<TData>
{
public:
typedef ZtCMutexCondData<TData> ZCMutexCondData;
public:
int WakeCond(){return this->WakeAllCond();}
public:
};/*
template< typename TData=ZNsMain::ZCEmpty ////////
>
class ZtCEventCond : public ZtCMutexCondData<TData>*/
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 <glib/gatomic.h>
namespace ZNsMain
{
/*///////////////////////////////////////////////////////
class ZtCAtomicIntSync<>
object
릿.
volatile gint .
lock-free .
int sched_yield(void) : IN <sched.h>
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 <unistd.h>.
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__