From 37628f49a47bc061f2b490720d2b627b00eb4d8c Mon Sep 17 00:00:00 2001 From: sauron Date: Thu, 4 Sep 2025 14:16:31 +0900 Subject: [PATCH] commit 2025-09-04 14:16 to tuf8 : ZCppMain/ZCProcess.H --- ZCppMain/ZCProcess.H | 2 +- ZCppMain/ZCProcess_Linux.H | 1252 ++++++++++++++++++++++---------------------- ZCppMain/ZCProcess_Win.H | 646 +++++++++++------------ 3 files changed, 950 insertions(+), 950 deletions(-) diff --git a/ZCppMain/ZCProcess.H b/ZCppMain/ZCProcess.H index 6834a4b..5677b88 100644 --- a/ZCppMain/ZCProcess.H +++ b/ZCppMain/ZCProcess.H @@ -1,4 +1,4 @@ - + #ifndef __ZCPPMAIN__PROCESS_H__ #define __ZCPPMAIN__PROCESS_H__ diff --git a/ZCppMain/ZCProcess_Linux.H b/ZCppMain/ZCProcess_Linux.H index 74a4fb0..1287311 100644 --- a/ZCppMain/ZCProcess_Linux.H +++ b/ZCppMain/ZCProcess_Linux.H @@ -1,4 +1,4 @@ - + #ifndef __ZCPPMAIN__PROCESS_LINUX_H__ #define __ZCPPMAIN__PROCESS_LINUX_H__ @@ -23,19 +23,19 @@ namespace ZNsMain /*//////////////////////////////////////////////////////////////////////// - κ Լ ϸ 0 ȯϴµ enum Ѵ. + ■ 대부분의 쓰레드 함수는 성공하면 0 을 반환하는데 이 값을 enum 지정한다. ////////////////////////////////////////////////////////////////////////*/ namespace ZNsEnum { - // Լ 쿡 å , ZEThread_Invalid ̿ ȯ ִ. + // 쓰레드 관련 함수가 에러일 경우에는 정책에 따라, ZEThread_Invalid 이외의 값을 반환할 수도 있다. enum ZEThread { ZEThread_OK =0 , - ZEThread_Invalid=EINVAL , // Լ . + ZEThread_Invalid=EINVAL , // 쓰레드 관련 함수 에러. ZEThread_TimeOut=ETIMEDOUT };/* enum ZEThread*/ @@ -43,9 +43,9 @@ namespace ZNsMain /*//////////////////////////////////////// - barrier ǥ ȯ. + ■ barrier 의 대표적인 반환값. - barrier üũ + ■ barrier 에러를 체크할 때 BarrierClass VO_BarrierClass; @@ -54,14 +54,14 @@ namespace ZNsMain // some code } - . + 로 하지 말고. if(VO_BarrierClass.Init()!=ZEBarrier_OK) { // some code } - ؾ ϴ. + 로 해야 안전하다. ////////////////////////////////////////*/ @@ -78,9 +78,9 @@ namespace ZNsMain /*///////////////////////////////////////////////////////////////////////////////////// - pthread ̺귯 ũ ɾ . + ■ 리눅스에서 pthread 라이브러리에 링크를 걸어줄 것. - 3.0 sys/sem.h ִ. + ■ 한컴 베포판 3.0 의 경우 sys/sem.h 에는 다음과 같은 설명이 나와 있다. The user should define a union like the following to use it for arguments for `semctl'. @@ -99,11 +99,11 @@ namespace ZNsMain #define _SEM_SEMUN_UNDEFINED 1 - IPC object ÷״ IPC_CREAT, IPC_EXCL, 0 ϳ̸, 0 ̸ ش - ȭ object . + ■ IPC object 의 플래그는 IPC_CREAT, IPC_EXCL, 0 의 세 값중의 하나이며, 0 이면 해당 동 + 기화 object 가 존재할 때만 연다. - Ͽ ִ Լ μ 쿡 ʰ ִ. - ׷ μ 쿡 Լ Ѵ. + 파일에 있는 세마포어 함수는 프로세스의 경우에는 지원되지 않고 있다. + 그래서 프로세스의 경우에는 의 세마포어 함수를 써야 한다. -- 2004-07-12 @@ -121,13 +121,13 @@ namespace ZNsMain /*////////////////////////////////////////////////////////////////// - 쿡 ȭ object ̸ ο ִµ, - Ű ο ִ. ׷ ȣȯ Ͽ ̸κ - Ű ϴ Լ . ̸ ȴٸ ftok() Լ + ■ 윈도우에서는 동기화 object 에 이름을 부여할 수 있는데, 리눅스에 + 서는 숫자키만 부여할 수 있다. 그래서 호환을 위하여 이름으로부터 + 키를 유추하는 함수를 만들었다. 파일 이름을 안다면 ftok() 함수 key_t ftok(const char *path, int id); - ϴ ͵ ̴. + 를 사용하는 것도 방법이다. //////////////////////////////////////////////////////////////////*/ @@ -153,15 +153,15 @@ namespace ZNsMain /*///////////////////////////////////////////////////////////////////////////// - ñ׳ ʴ´. ̺Ʈ ̾ ټ ߻ߴٰ ؼ - μ ñ׳ ټ ʴ´. ̷ - sa_mask ذ ִ. sa_mask ñ׳ε ̺Ʈ - ̼ ټ ߻ϴ ñ׳ ߻Ų. ù° ñ - óǴ ñ׳ε ŷ ¿ ְ ȴ. + ■ 시그널은 쌓이지 않는다. 즉 동일한 이벤트가 연이어서 다섯 번 발생했다고 해서 + 프로세서에게 동일한 시그널을 다섯 번 전달해 주지 않는다. 이러한 문제점은 + sa_mask 를 통해 해결할 수 있다. sa_mask 에 설정된 시그널들은 동일한 이벤트가 + 연이이서 다섯번 발생하는 경우 순차적으로 시그널을 발생시킨다. 즉 첫번째 시그 + 널이 처리되는 동안 나머지 시그널들은 블로킹 상태에 있게 된다. - -- TCP/IP α׷ ( ) 245 Page + -- TCP/IP 소켓 프로그래밍 (윤성우 저) 245 Page - ߿ Ansi, Posix ñ׳ + ■ 중요 Ansi, Posix 시그널 정의 #define SIG_ERR ((__sighandler_t) -1) // Error return. #define SIG_DFL ((__sighandler_t) 0) // Default action. @@ -191,134 +191,134 @@ namespace ZNsMain #define SIGSYS 31 // Bad system call #define SIGUNUSED 31 - SIGHUP + ◇ SIGHUP - - ͹̳ ̽ Ǹ ش ͹̳ΰ μ( ) - - ߻ϴµ ̶ foreground μ ׷쳻 μ鿡 - - SIGHUP ñ׳ ø ߻ϴ ñ׳̴. - - ̸ ִ ý SIGHUP ñ׳ configure file ٽ о̴ ʱȭ ȣ ؼѴ. + - 터미널 인터페이스에 의해 연결의 단절이 감지되면 해당 제어 터미널과 연결된 제어 프로세스(세션 리더)에게 전달 + - 세션 리더가 종료했을 때도 발생하는데 이때는 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 ϱ ִ. + . pppd(8) 처럼 SIGHUP을 원래의 의도에 충실하게 세션 종료의 뜻으로 받아들이는 사례도 간혹 있는데, 요새는 보편적으로 이 역할을 SIGTERM이 맡는다. + . daemon은 제어 단말기 없이 돌기 때문에 kernel로부터 SIGHUP 신호를 수신하지 못한다. + 그러므로 많은 daemon은 이 신호를 daemon의 구성 파일이 변경되어 daemon이 그 파일을 새로 읽어야 된다는 것을 알려주는 관리자로부터의 통지로 사용한다. + . daemon이 수신할 수 없는 다른 두 개의 신호로 SIGINT와 SIGWINCH가 있고 이들도 역시 어떤 변화를 daemon에게 통지하기 위해 사용될 수 있다. - SIGINT + ◇ SIGINT - - ͷƮ Ű (DELETE Ǵ Control-C) ߻ + - 인터럽트 키 (DELETE 또는 Control-C)가 눌렸을 때 발생 - SIGQUIT + ◇ SIGQUIT - - Control-backslash ߻ + - Control-backslash 에 의해 발생 - SIGCHLD + ◇ SIGCHLD - - μ ϰų ϸ, θ μ ޵ȴ. - - θ μ wait() ý Ͽ Ͼ ˾ƺ. - - ñ׳ο default ó ϴ ̴. μ ȣ ޵ȴ. + - 프로세스가 종료하거나 정지하면, 부모 프로세스에게 전달된다. + - 부모 프로세스는 wait() 시스템 콜을 사용하여 무슨 일이 일어났는지 알아본다. + - 이 시그널에 대한 default 처리는 무시하는 것이다. 즉 프로세스가 이 신호를 받으려고 할 때만 전달된다. - SIGSEGV + ◇ SIGSEGV - - ȿ ޸ ּҸ ϰų ޸𸮿 μ ޵ȴ. + - 유효하지 않은 가상 메모리 주소를 참조하거나 사용 권한이 없는 메모리에 접근할 때 프로세스로 전달된다. - SIGTERM + ◇ SIGTERM - - kill ɿ ⺻ ߻ + - kill 명령에 의해 기본적으로 발생 - SIGKILL + ◇ SIGKILL - - "ش ġ(extreme prejudice)" α׷ ϴ ȴ. - - ñ׳ catch ϰų . + - "극단의 조치(extreme prejudice)"로 프로그램을 종료하는 데 사용된다. + - 시그널 catch 하거나 무시할 수 없다. - SIGALRM + ◇ SIGALRM - - alarm()̳ setitimer() ý ݷ ˶ ð ʰ μ ޵ȴ. + - alarm()이나 setitimer() 시스템 콜로 설정한 알람 시간이 초과 했을 때 프로세스로 전달된다. - SIGTSTP + ◇ SIGTSTP - - Control-Z Ű ߻ - - ⺻ ó SIGCONT ȣ μ ߴѴ. + - Control-Z 키에 의해 발생 + - 기본 처리 방법은 SIGCONT 신호를 받을 때까지 프로세스를 중단한다. - SIGCONT + ◇ SIGCONT - - μ Ű ߻ - - ȣ ϰų . - - ⺻ ó ߴܵ μ ϴ ̴. ׷ μ ȣ ʴ´ٸ ȣ . - - vi ͸ - . Control-Z Ű Ű Է óϰ Ǵµ - . ̶ fg Ű vi SIGCONT ñ׳ ϸ - . vi ñ׳ο ó ȭ ٽ ׸ Ű Է ޴ · ư. + - 정지한 프로세스를 계속 실행시키려 할 때 발생 + - 이 신호는 받을 수 있지만 블록하거나 무시할 수 없다. + - 기본 처리 방법은 중단된 프로세스를 재시작하는 것이다. 그러나 프로세스가 신호를 받지 않는다면 신호를 버린다. + - vi 에디터를 사용할 때 + . Control-Z 를 눌러 수행을 잠시 정지시키면 쉘이 키 입력을 처리하게 되는데 + . 이때 fg 명령을 실행시키면 쉘은 vi 에게 SIGCONT 시그널을 전달하며 + . vi는 이 시그널에 대한 처리로 화면을 다시 그리고 사용자 키 입력을 받는 상태로 돌아간다. - SIGSTOP + ◇ SIGSTOP - - SIGTSTP ϳ catch ϰų . - - ȣ SIGCONT ȣ μ ߴѴ. + - SIGTSTP과 동일하나 catch 하거나 무시할 수 없다. + - 이 신호를 받으면 무조건 SIGCONT 신호를 받을 때까지 프로세스를 중단한다. - SIGABRT + ◇ SIGABRT - - abort() Լ ȣ ߻ + - abort() 함수의 호출로 발생 - SIGBUS + ◇ SIGBUS - - ϵ ߻ + - 하드웨어 결함으로 발생 - SIGEMT + ◇ SIGEMT - - ϵ ߻ + - 하드웨어 결함으로 발생 - SIGFPE + ◇ SIGFPE - - divide-by-0 ε Ҽ ÷ο ߻ + - divide-by-0나 부동 소숫점 오버플로우와 같은 산술 연산 오류에서 발생 - SIGILL + ◇ SIGILL - SIGINFO + ◇ SIGINFO - SIGIO + ◇ SIGIO - SIGIOT + ◇ SIGIOT - SIGPIPE + ◇ SIGPIPE - - pipe ſ μ ۽ μ write ϸ ߻ - - μ RST Ͽ ͸ , Ŀ μ ISGPIPE ȣ . - - ȣ ⺻ μ Ű ̹Ƿ, μ ʴ Ḧ ϱ ؼ ȣ ؾ Ѵ. + - pipe 통신에서 수신 프로세스가 종료했을 때 송신 프로세스가 파이프에 write 하면 발생 + - 프로세스가 RST를 받은 소켓에 데이터를 쓰면, 커널은 그 프로세스에 ISGPIPE 신호를 보낸다. + - 이 신호의 기본 동작은 프로세스를 종료시키는 것이므로, 프로세스가 원하지 않는 종료를 피하기 위해서는 이 신호를 포착해야 한다. - SIGPOLL + ◇ SIGPOLL - SIGROF + ◇ SIGROF - SIGPWR + ◇ SIGPWR - SIGSYS + ◇ SIGSYS - SIGTTIN + ◇ SIGTTIN - - background ִ μ ͹̳ηκ б⸦ õѴ. + - background에 있는 프로세스가 제어 터미널로부터의 읽기를 시도한다. - SIGTTOU + ◇ SIGTTOU - - background ִ μ ͹̳ηκ ⸦ õѴ. + - background에 있는 프로세스가 제어 터미널로부터의 쓰기를 시도한다. - SIGURG + ◇ SIGURG - - SIGIO SIGURG ȣ F_SETOWN ֿ ҴǾ Ͽ ߻Ѵ. + - SIGIO와 SIGURG 라는 두 개의 신호는 소켓이 F_SETOWN 명령으로 소유주에게 할당되었을 때만 소켓에 대해 발생한다. - SIGUSR1 + ◇ SIGUSR1 - SIGUSR2 + ◇ SIGUSR2 - SIGVTALRM + ◇ SIGVTALRM - SIGWINCH + ◇ SIGWINCH - SIGXCPU + ◇ SIGXCPU - SIGXFSZ + ◇ SIGXFSZ - -- 2009-11-29 00:26:00 + ■ -- 2009-11-29 00:26:00 - linux sigaction -- 2011-06-05 22:55:00 + ■ linux 에서의 sigaction 정의 -- 2011-06-05 22:55:00 struct sigaction { union { @@ -333,7 +333,7 @@ namespace ZNsMain #define sa_handler _u._sa_handler #define sa_sigaction _u._sa_sigaction - solaris sigaction -- 2011-06-05 22:56:00 + ■ solaris 에서의 sigaction 정의 -- 2011-06-05 22:56:00 struct sigaction { int sa_flags; @@ -358,7 +358,7 @@ namespace ZNsMain #define sa_handler _funcptr._handler #define sa_sigaction _funcptr._sigaction - freebsd sigaction -- 2011-06-05 22:59:00 + ■ freebsd 에서의 sigaction 정의 -- 2011-06-05 22:59:00 struct sigaction { union { void (*__sa_handler)(int); @@ -393,7 +393,7 @@ namespace ZNsMain void SetFlags(int AI_Flags) { - this->sa_flags=AI_Flags; // RTS SA_SIGINFO + this->sa_flags=AI_Flags; // RTS 에는 SA_SIGINFO 를 셋팅 }/* void SetFlags(int AI_Flags)*/ @@ -405,7 +405,7 @@ namespace ZNsMain void SetHandlerEx(void (*APF_Handler)(int, siginfo_t*, void*)) { - this->sa_sigaction=APF_Handler; // ַ RTS + this->sa_sigaction=APF_Handler; // 주로 RTS 에서 사용됨 }/* void SetHandlerEx(void (*APF_Handler)(int, siginfo_t*, void*))*/ @@ -444,9 +444,9 @@ namespace ZNsMain { return ::alarm(AI_Sec); - /* AI_Sec 0 ˶ û . ˶ ȣ - ޵DZ ִ ð ȯϰų ȣ - ϸ -1 ȯѴ. */ + /* AI_Sec 0 은 나머지 알람 요청을 취소. 나머지 알람 호출 + 이 전달되기 전에 남아있는 시간을 반환하거나 호출이 + 실패하면 -1 을 반환한다. */ }/* static ZTypUInt Alarm(ZTypUInt AI_Sec)*/ @@ -461,14 +461,14 @@ namespace ZNsMain /*///////////////////////////////////////////////////////////////////////// - freebsd 8.2, solaris 5.11 F_SETSIG ǰ Ǿ ʾƼ, - Ʒ SetupRTS() Լ . RTS . + ■ freebsd 8.2, solaris 5.11 에서는 F_SETSIG 이 정의가 되어 있지 않아서, + 아래 SetupRTS() 함수를 사용할 수 없다. 즉 RTS 와 소켓을 연동할 수 없다. -- 2011-06-09 04:25:00 /////////////////////////////////////////////////////////////////////////*/ - // ַ SIGRTMIN ~ SIGRTMAX ̿ ִ RTS Ѵ. + // 주로 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()) { @@ -548,27 +548,27 @@ namespace ZNsMain /*////////////////////////////////////////////////////////////// - int AI_How ִ . + ■ 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. @@ -592,7 +592,7 @@ namespace ZNsMain /*////////////////////////////////////////////////////////////////// - SYNOPSIS + ■ SYNOPSIS #include @@ -603,7 +603,7 @@ namespace ZNsMain siginfo_t *restrict info, const struct timespec *restrict timeout); - RETURN VALUES + ■ RETURN VALUES Upon successful completion (that is, one of the signals specified by set is pending or is generated) sigwaitinfo() @@ -611,7 +611,7 @@ namespace ZNsMain Otherwise, the function returns -1 and sets errno to indi- cate the error. - ERRORS + ■ ERRORS The sigwaitinfo() and sigtimedwait() functions will fail if: @@ -639,7 +639,7 @@ namespace ZNsMain no signal is pending in set and it is necessary to wait. - -- 2011-06-02 01:14:00 + ■ -- 2011-06-02 01:14:00 //////////////////////////////////////////////////////////////////*/ @@ -652,7 +652,7 @@ namespace ZNsMain /*////////////////////////////////////////////////////////////////// - SYNOPSIS + ■ SYNOPSIS #include #include @@ -661,14 +661,14 @@ namespace ZNsMain int sigqueue(pid_t pid, int signo, const union sigval value); - RETURN VALUES + ■ 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 + ■ ERRORS The sigqueue() function will fail if: @@ -690,7 +690,7 @@ namespace ZNsMain ESRCH The process pid does not exist. - -- 2011-06-02 01:40:00 + ■ -- 2011-06-02 01:40:00 //////////////////////////////////////////////////////////////////*/ @@ -706,7 +706,7 @@ namespace ZNsMain // cf) typedef int pid_t - // 뵵ε Լ̴. + // 데몬을 만드는 용도로도 가능한 함수이다. bool Exec(const char* AP_ExeName, bool AB_DoCloseStdInOut=true) { @@ -718,18 +718,18 @@ namespace ZNsMain { /*///////////////////////////////////////////////////////////////// - APA_Arg Ҵ NULL Ѵ. + ■ APA_Arg 의 마지막 원소는 NULL 로 끝나야 한다. char *aRgu[4]; aRgu[0] = "/test/test.exe"; aRgu[1] = "ABC"; // Argu 1 aRgu[2] = "10" ; // Argu 2 - aRgu[3] = 0 ; // ƱԸƮ ̶ ͸ Ͽ Ѵ. + aRgu[3] = 0 ; // 아규먼트가 끝이라는 것를 꼭 지정하여야 한다. execvp(aRgu[0] , aRgu); - execl + ■ execl 사용례 ::execl( "./WinSEC_D.exe" , "./WinSEC_D.exe" , @@ -752,7 +752,7 @@ namespace ZNsMain }/* if(AB_DoCloseStdInOut==true)*/ - ::setsid(); // ڱ ڽ . + ::setsid(); // 자기 자신을 세션의 리더로 만든다. ::execvp(AP_ExeName, APA_Arg); return true; @@ -761,7 +761,7 @@ namespace ZNsMain { return false; } - else // θ + else // 부모의 경우 { return true; }/* @@ -810,147 +810,147 @@ namespace ZNsMain /*///////////////////////////////////////////////////////////////////////////// - SHMGET(2) α׷ ޴ SHMGET(2) + SHMGET(2) 리눅스 프로그래머 메뉴얼 SHMGET(2) - ̸ + ■ 이름 - shmget - ޸ ׸Ʈ ҴѴ. + shmget - 공유 메모리 세그먼트를 할당한다. - + ■ 사용법 #include #include int shmget(key_t key, int size, int shmflg); - - shmget() key ڰ õ ޸ ׸Ʈ ĺڸ ȯѴ. - , key IPC_PRIVATE ְų Ǵ key IPC_PRIVATE - ϰ, key Ǿ ִ ޸ ׸Ʈ ٸ PAGE_SIZE - ŭ size ִ ο ޸ ׸Ʈ - . IPC_CREAT shmflg õǾ ִ. (i.e. shmflg&IPC_CREAT - 0 ƴϴ.) + ■ 설명 + shmget() 는 key 인자값과 관련된 공유 메모리 세그먼트 식별자를 반환한다. + 만일, key 가 IPC_PRIVATE 값을 가지고 있거나 또는 key 가 IPC_PRIVATE 가 + 아 니고, key 와 연계되어 있는 공유메모리 세그먼트가 없다면 PAGE_SIZE 의 + 배수만큼의 size 를 가지고 있는 새로운 공유 메모리 세그먼트가 만들 어 진 + 다. IPC_CREAT 는 shmflg 에 명시되어 있다. (i.e. shmflg&IPC_CREAT 는 + 0이 아니다.) - shmflg : + shmflg 의 구성은 다음과 같다: - IPC_CREAT ο ׸Ʈ . ÷װ ʴ - , shmget() key õ ׸Ʈ ã ̸, - ׸Ʈ õ shmid 㰡 ִ - ؼ ˻Ѵ. ׸ ׸Ʈ ıǾٴ ǥø - ʵ Ѵ. + IPC_CREAT 새로운 세그먼트를 만든다. 만일 이 플래그가 사용되지 않는 다 + 면, shmget() 는 key와 관련된 세그먼트를 찾을 것이며, 사용자 + 가 그 세그먼트와 관련된 shmid 를 받을 허가권이 있는지 알 기 + 위해서 검사한다. 그리고 세그먼트가 파괴되었다는 표시를 하지 + 않도록 보장한다. - IPC_EXCL ׸Ʈ Ұ и ϱ IPC_CREAT Բ - ȴ. + IPC_EXCL 세그먼트가 존재할경우 실패를 보장하기 위해 IPC_CREAT와 함께 + 사용된다. mode_flags (lowest 9 bits) - , ׷, ܵ ϱ 㰡 Ѵ. - , 㰡 ýۿ ʴ´. + 소 유 자, 그룹, 그 외들을 보장하기 위해 허가권을 지정한다. + 현재, 실행 허가권은 시스템에 의해 사용되지 않는다. - ο ׸Ʈ ȴٸ, shmflg 㰡׸Ʈ - ִ shmid_ds shm_perm ȴ. shmid_ds ü: + 새로운 세그먼트가 생성된다면, 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 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 uid; // 소유자의 euid 와 egid ushort gid; - ushort cuid; // euid egid + ushort cuid; // 생성자의 euid 와 egid ushort cgid; - ushort mode; // shmflg 9Ʈ - ushort seq; // (sequence number) + ushort mode; // shmflg의 하위 9비트 + ushort seq; // 연속 수(sequence number) }; - Դٰ, Ǵ ý ý ޸ ׸Ʈ - shmid_ds ʱȭѴ. + 게다가, 생성되는 동안 시스템 콜은 시스템 공유 메모리 세그먼트 데이터 구 + 조 shmid_ds 를 다음과 같이 초기화한다. - shm_perm.cuid shm_perm.uid ȣ μ ȿ user-ID - ȴ. + shm_perm.cuid 와 shm_perm.uid 는 호출 프로세스의 유효 user-ID 로 + 설정된다. - shm_perm.cgid shm_perm.gid ȣ μ ȿ group-ID - ȴ. + shm_perm.cgid 와 shm_perm.gid 는 호출 프로세스의 유효 group-ID로 + 설정된다. - shm_perm.mode 9Ʈ shmflg 9Ʈ - . + shm_perm.mode 의 하위 9비트들은 shmflg 의 하위 9비트들로 설정 된 + 다. - shm_segsz size ȴ. + shm_segsz 는 size 값으로 설정된다. - shm_lpid, shm_nattch, shm_atime ׸ shm_dtime 0 - ȴ. + shm_lpid, shm_nattch, shm_atime 그리고 shm_dtime 는 0 으로 설정 + 된다. - shm_ctime ð ȴ. + shm_ctime 는 현재 시간으로 설정된다. - ޸ ׸Ʈ ̹ Ѵٸ, 㰡 Ǹ, - ǥõǾ ִ ˾ƺ ˻Ѵ. + 만일 공유 메모리 세그먼트가 이미 존재한다면, 접근 허가권이 조사되며, 파 + 괴도도록 표시되어 있는지 알아보기 위해 검사한다. - SYSTEM CALLS + ■ SYSTEM CALLS - fork() fork() Ŀ ڽ μ ޸ ׸Ʈ - Ѵ. + fork() fork() 후에 자식 프로세스는 연결된 공유 메모리 세그먼트들을 상속 + 한다. - exec() exec() Ŀ ޸ ׸Ʈ иȴ.(ı - ° ƴϴ) + exec() exec() 후에 연결된 모든 공유 메모리 세그먼트는 분리된다.(파괴 되 + 는것이 아니다) - exit() exit() ޸ ׸Ʈ иȴ.(ıǴ - ƴϴ) + exit() exit() 시 연결된 모든 공유 메모리 세그먼트는 분리된다.(파괴되는 + 것이 아니다) - ȯ + ■ 반환값 - ȿ ׸Ʈ ĺ shmid ȯǸ, -1 ȯ . + 성공시 유효한 세그먼트 식별자 shmid 가 반환되며, 에러시 -1이 반환된 다. - + ■ 에러 - н, errno ϳ ȴ: + 실패시, errno 는 다음중 하나로 설정된다: - EINVAL SHMMIN > size, Ǵ size > SHMMAX, Ǵ size ׸ - Ʈ ũ⺸ ũٸ ̿ ȯȴ. + EINVAL 만일 SHMMIN > size, 또는 size > SHMMAX, 또는 size이 세그먼 + 트의 크기보다 크다면 이에러가 반환된다. - EEXIST IPC_CREAT | IPC_EXCL Ǿ ְ, - ׸Ʈ ȯȴ. + EEXIST IPC_CREAT | IPC_EXCL 이 지정되어 있고, + 세그먼트가 존재하 면 이 에러가 반환된다. - EIDRM ׸Ʈ ı ŵǵ ǥõǾ ִٸ ȯȴ. + EIDRM 세그먼트가 파괴나 제거되도록 표시되어 있다면 이 에러가 반환된다. - ENOSPC ޸ id (SHMMNI) ų û size - ׸Ʈ Ҵ ý ü ޸ Ѱ (SHMALL) ʰҰ ȯȴ. + ENOSPC 가능한 모든 공유 메모리 id (SHMMNI) 를 가졌거나 요청된 size 의 + 세그먼트 할당이 시스템 전체 공유 메모리 제한값 (SHMALL) 을 초과할경우 반환된다. - ENOENT ־ key شϴ ׸Ʈ ʰ, - IPC_CREAT ʾҴٸ ȯȴ. + ENOENT 주어진 key에 해당하는 세그먼트가 존재하지 않고, + IPC_CREAT 가 지정되지 않았다면 반환된다. - EACCES ڰ ޸ ׸Ʈ 㰡 ȯȴ. + EACCES 사용자가 공유 메모리 세그먼트에 대한 접근 허가권이 없을때 반환된다. - ENOMEM ׸Ʈ Ҵ ޸𸮰 ȯȴ. + ENOMEM 세그먼트를 위해 할당할 메모리가 없을때 반환된다. - + ※ 주의 - IPC_PRIVATE ÷ ʵ尡 ƴ϶ key_t Ÿ̴. Ư key - ȴٸ, ý shmflg 9Ʈ Ѵ. - ׸ ޸ ׸Ʈ ()Ѵ. + IPC_PRIVATE 는 플레그 필드가 아니라 key_t 타입이다. 이 특별한 값이 key에 + 사용된다면, 시스템 콜은 shmflg 의 하위 9비트들외 모든것을 무시한다. + 그리고 새 공유 메모리 세그먼트를 생성(성공시)한다. - shmget ý ݿ ִ ޸ ׸Ʈ ڿ Ѱ̴: + 다음은 shmget 시스템 콜에 영향을 주는 공유 메모리 세그먼트 자원들의 제한값들이다: - SHMALL ý ü ޸ ׸Ʈ ִ : å ̴. - SHMMAX ޸ ׸Ʈ ִ ũ(Ʈ): ̴.( 4M) - SHMMIN ޸ ׸Ʈ ּ ũ(Ʈ): ̴. - (PAGE_SIZE ȿ ּ ũ, 1byte̴.) - SHMMNI ý ü ޸ ׸Ʈ ִ : ̴( 4096) + SHMALL 시스템 전체의 공유 메모리 세그먼트 최대 값: 정책 의존적이다. + SHMMAX 공유 메모리 세그먼트의 최대 크기(바이트수): 수행 의존적이다.(현재 4M) + SHMMIN 공유 메모리 세그먼트의 최소 크기(바이트수): 수행 의존적이다. + (PAGE_SIZE 가 유효한 최소 크기이지만, 현재는 1byte이다.) + SHMMNI 시스템 전체의 공유 메모리 세그먼트 최대 수: 수행 의존적이다(현재 4096) - μ ޸ ׸Ʈ Ư . (SHMSEG) + 수행시 프로세스당 공유 메모리 세그먼트의 특별한 제한은 없다. (SHMSEG) /////////////////////////////////////////////////////////////////////////////*/ - // ޸ Ŭ + // 공유메모리 클래스 class ZCShareMemory { @@ -1031,7 +1031,7 @@ namespace ZNsMain bool ShmGet(long AL_MapID) { - // key AL_MapID ޸𸮰 ִ + // key 가 AL_MapID 인 공유메모리가 있는지 조사 return (mh_FileMap=::shmget((key_t)AL_MapID, 0, 0))!=-1 ; }/* @@ -1044,8 +1044,8 @@ namespace ZNsMain return (mp_Address=::shmat(mh_FileMap, (void*)0, 0))!=NULL ; - // shmat() 3 ° μ SHM_RDONLY ÷׸ ϸ - // ޸ ׸Ʈ εǾ, б(readonly) ǥõȴ + // shmat() 의 3 번째 인수로 SHM_RDONLY 플래그를 지정하면 + // 공유 메모리 세그먼트는 매핑되어지지만, 읽기전용(readonly)로 표시된다 }/* bool LinkMap()*/ @@ -1063,11 +1063,11 @@ namespace ZNsMain mh_FileMap=EInvalidID; return VB_IsOK; - /* IPC_RMID ɾ Ŀη ׸Ʈ ϴ ƴϴ. - ϱ ׸Ʈ ǥø صд. ü ׸Ʈ - پ ִ(attached) μ и(detached) Ͼ. - , ׸Ʈ پִ (attached) μ , Ŵ - ̷ . */ + /* IPC_RMID 명령어는 실제로 커널로 부터 세그먼트를 제거하는 것은 아니다. + 제거하기 위해 세그먼트에 표시를 해둔다. 실제적인 제거 자체는 현재 세그먼트에 + 붙어 있는(attached) 마지막 프로세스가 적절히 분리됐을(detached) 때 일어난다. + 물론, 현재 세그먼트에 붙어있는 (attached) 프로세스가 없으면, 제거는 즉시 + 이루어 진다. */ }/* bool Close()*/ @@ -1078,14 +1078,14 @@ namespace ZNsMain /*//////////////////////////////////////////////////////////////////////////////////////// - class ZCProcessMutex μ ؽ. + ■ class ZCProcessMutex 는 프로세스의 뮤텍스. - Window ̸ִ mutex , Linux  ִ. - pthread ̺귯 Ἥ ޸𸮿 mutex Ÿ ־ ׸ŭ ܼ - ʿϴ. + Window 에서는 이름있는 mutex 를 쓰면 간단하지만, Linux 에서는 세마포어를 쓸 수도 있다. + pthread 라이브러리를 써서 공유메모리에 mutex 데이타를 넣어도 되지만 그만큼 잔손질이 + 필요하다. - Linux ߾忡 μ  ٸ. - Ȯ pthread μ  ʴ´. (2006-12-28 16:02:00) + Linux 에서는 다중쓰레드에서 쓰는 세마포어와 다중 프로세스에서 쓰는 세마포어가 다르다. + 정확히는 pthread 가 프로세스 세마포어를 아직 지원하지 않는다. (2006-12-28 16:02:00) ////////////////////////////////////////////////////////////////////////////////////////*/ @@ -1097,8 +1097,8 @@ namespace ZNsMain bool Init(int AI_InitNum=1) { - // - // ʱȭѴ. + // 리눅스에서만 가능 + // 세마포어의 값을 초기화한다. union semun SemUnion; SemUnion.val=AI_InitNum; @@ -1141,9 +1141,9 @@ namespace ZNsMain ZTypeID GetHandle() const*/ - // Linux μ Window μ ؽ Ѵ. - // Window ؽ μ Linux - // 쿡 ׷ ʴ. 2006-08-06 15:55:00 + // Linux 의 경우 프로세스 세마포어로 Window 의 프로세스 뮤텍스를 구현한다. + // Window 의 뮤텍스는 쓰레드와 프로세스에 모두 사용할 수 있지만 Linux 의 + // 경우에는 그렇지 않다. 2006-08-06 15:55:00 bool Make(const char* AP_MutexName, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) { @@ -1153,8 +1153,8 @@ namespace ZNsMain bool Make(long AL_KeyID, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) { - // AI_Flag IPC_CREAT,IPC_EXCL,0 ϳ̸ - // 0 ̸ ش ȭobject . + // AI_Flag 는 IPC_CREAT,IPC_EXCL,0 의 세 값중의 하나이며 + // 0 이면 해당 동기화object 가 존재할 때만 연다. // int semget(key_t key,int nsems,int semflg) @@ -1177,7 +1177,7 @@ namespace ZNsMain bool Lock() { struct sembuf sembuf_Obj; - sembuf_Obj.sem_num= 0; // semaphore 迭 ° semaphore + sembuf_Obj.sem_num= 0; // semaphore 배열에서 몇 번째 semaphore 인지를 지정 sembuf_Obj.sem_op =-1; sembuf_Obj.sem_flg=SEM_UNDO; @@ -1188,7 +1188,7 @@ namespace ZNsMain bool UnLock() { struct sembuf sembuf_Obj; - sembuf_Obj.sem_num=0 ; // semaphore 迭 ° semaphore + sembuf_Obj.sem_num=0 ; // semaphore 배열에서 몇 번째 semaphore 인지를 지정 sembuf_Obj.sem_op =1 ; sembuf_Obj.sem_flg=SEM_UNDO; @@ -1198,11 +1198,11 @@ namespace ZNsMain bool Close() { - // Ŀο semaphore ŵȴ. Լ Ŀ ipcs - // semaphore Ͽ Ÿ ʴ´. Ŀ Lock() - // ϰ ִ μ Ѳ  ̻ - // ȭ ʴ´. μ Լ ʰ ص Ŀ - // ڵ semaphore ʴ´. + // 커널에서 semaphore 가 제거된다. 이 함수 수행후에 ipcs 해 보면 + // semaphore 목록에 나타나지 않는다. 따라서 이 함 수행 후에는 Lock() + // 에서 대기하고 있던 프로세스나 쓰레드는 한꺼번에 깨어나고 더이상 + // 동기화되지 않는다. 프로세스가 이 함수를 수행하지 않고 종료해도 커 + // 널은 자동적으로 semaphore 를 삭제하지 않는다. union semun SemUnion; @@ -1227,7 +1227,7 @@ namespace ZNsMain - // posix mutex μ ȭ ϴ Ŭ + // posix mutex 로 프로세스간 동기화를 하는 클래스 class ZCProcessMutexPosix @@ -1291,7 +1291,7 @@ namespace ZNsMain ::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_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); }/* @@ -1312,7 +1312,7 @@ namespace ZNsMain { return ::pthread_mutex_lock(&mp_MutexData->mo_PThreadMutex); - // EDEADLK ȯϴ 츦 üũ . + // EDEADLK 를 반환하는 경우를 체크할 것. }/* int Lock()*/ @@ -1334,10 +1334,10 @@ namespace ZNsMain { return ::pthread_mutex_timedlock(&mp_MutexData->mo_PThreadMutex, &AR_TimeSpec); - // ̸ ZNsEnum::ZEThread_OK - // ðʰ̸ ZNsEnum::ZEThread_TimeOut + // 성공이면 ZNsEnum::ZEThread_OK 를 + // 시간초과이면 ZNsEnum::ZEThread_TimeOut 를 리턴 // - // EDEADLK ȯϴ 츦 üũ . + // EDEADLK 를 반환하는 경우를 체크할 것. }/* int Lock(const struct timespec& AR_TimeSpec)*/ @@ -1385,17 +1385,17 @@ namespace ZNsMain /*//////////////////////////////////////////////////////////////////////////////// - /ǵ lock(read-write lock) Window ̺Ʈ - ִ. Ư ټ 尡 ϴٰ ÿ  - . ؽ Ǻ ̺Ʈ ϴ ȿ̴. + ■ 기록자/판독자 lock(read-write lock) 으로 Window 의 수동리셋 이벤트를 구현할 수 + 있다. 즉 특정 지점에서 다수의 쓰레드가 대기하다가 동시에 깨어나는 동작이 가능하 + 다. 물론 뮤텍스 조건변수로 수동리셋 이벤트를 구현하는 것이 더 효과적이다. - POSIX.1b structure for a time value. + ■ 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 + long int tv_nsec; // Nanoseconds. 10 억분의 1 초, 1 밀리초=1000*1000 나노초 }; ////////////////////////////////////////////////////////////////////////////////*/ @@ -1518,9 +1518,9 @@ namespace ZNsMain bool GetShared(int& ARRI_PShared)*/ - // ǵ, lock 켱 Լ, Posix ǥ ƴϴ. - // Լ 켱 ʾҴٸ ⺻ lock - // 켱 δ ִ . -- 2006-12-30 16:21:00 + // 판독자,기록자 lock 의 우선순위 관련 함수, 현재 Posix 표준이 아니다. + // 이 함수로 우선순위를 설정하지 않았다면 기본적으로 기록자 lock 에 + // 우선순위를 두는 것으로 설정되있는 베포판이 많다. -- 2006-12-30 16:21:00 int GetKind(int& ARRI_Kind) const { @@ -1697,15 +1697,15 @@ namespace ZNsMain /*////////////////////////////////////////////////////////////////////////////////// - class ZCProcessSemaphore μ ȭ object. μ - ȭ Semaphore ְ, Window μ ȭ Mutex - ִ. μ ȭ ̴ Semaphore ȭ ̴ -  Լ ٸ. + ■ class ZCProcessSemaphore 는 프로세스만을 위한 동기화 object. 리눅스에서는 프로세스 + 동기화에 Semaphore 만 쓸 수 있고, Window 에서는 프로세스 동기화에 Mutex 도 쓸 수 + 있다. 리눅스에서는 프로세스 동기화에 쓰이는 Semaphore 와 스레드 동기화에 쓰이는 + 세마포어가 함수와 용법이 다르다. - ý ȣ : semget() (SYSTEM CALL:semget()) + ■ 시스템 호출 : semget() (SYSTEM CALL:semget()) - ο ų ϴ տ ϱ Ͽ, semget() ý ȣ - Ѵ. + 새로운 세마퍼 집합을 만들거나 존재하는 집합에 접근하기 위하여, semget() 시스템 호출 + 을 사용한다. SYSTEM CALL: semget(); @@ -1717,32 +1717,32 @@ namespace ZNsMain ENOENT (set does not exist, no IPC_CREAT was used) ENOMEM (Not enough memory to create new set) ENOSPC (Maximum set limit exceeded) - NOTES: + □ NOTES: - semget() ù° ƱԸƮ ftok() ȣ⿡ ȯ Ű̴. - Ű Ŀξȿ ϴ ٸ Ű 񱳵ȴ. ̶ ų ϴ semflg ƱԸƮ 뿡 ȴ. + semget()의 첫번째 아규먼트는 ftok()의 호출에 의해 반환된 키값이다. + 이 키값은 커널안에 존재하는 다른 세마퍼 집합의 키값과 비교된다. 이때 열거나 접근하는 동작은 semflg 아규먼트의 내용에 따라 결정된다. IPC_CREAT - Ŀξȿ ̹ ʴ´ٸ . + 커널안에 이미 존재하지 않는다면 세마퍼 집합을 만든다. IPC_EXCL - IPC_CREAT Ǿ, ۰ ̹ ϸ Ѵ. + IPC_CREAT와 같이 사용되어, 세마퍼가 이미 존재하면 실패한다. - IPC_CREAT ȥ ȴٸ, semget() Ȯ - (the semaphore set identifier) ȯϰų Ű ̹ ϴ - Ȯڸ ȯѴ. IPC_EXCL IPC_CREAT Բ ٸ, - ų ̹ Ѵٸ -1 ȣ⿡ Ѵ. - IPC_EXCL üδ ǹ̰ , IPC_CREAT յǾ - ʴ ۸ (access)ϱ ġ ִ. - ý V IPC ٸ µó ΰ 8 尡 㰡 ¿ ũ OR ִ. + 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 Ǿִ. + nsems 아규먼트는 새 집합안에서 만들어져야 하는 세마퍼의 갯수를 지정한다. + 이것은 앞에서 설명했던 가상의 인쇄방의 프린터의 갯수를 의미한다. + 집합안의 최대 세마퍼의 갯수는 linux/sem.h에 정의 되어있다. - #define SEMMSL 32 // <=512 id ִ + #define SEMMSL 32 // <=512 id당 세마퍼의 최대 갯수 - ̹ ϴ Ȯ ִٸ, nsems ƱԸƮ õʿ ָض. - wrapper Լ : + 이미 존재하는 집합을 명확히 열고 있다면, nsems 아규먼트는 무시됨에 주목해라. + 세마퍼 집합을 만들고 여는 wrapper 함수를 만들어 보자: int open_semaphore_set( key_t keyval, int numsems ) { @@ -1758,15 +1758,15 @@ namespace ZNsMain } //int open_semaphore_set( key_t keyval, int numsems ) - 0600 㰡 Կ ض. - Լ Ȯ(int) ȯϰų -1 ȯѴ. - ٸ, Ҵϱ Ű Ѱ Ѵ. - ǥ , ϴ ʴ - ϱ IPC_EXCL ÷ 뿡 ָض + 0600의 명시적인 허가사항을 사용함에 주의해라. + 이 작은 함수는 세마퍼 집합 확인자(int)를 반환하거나 에러시 -1을 반환한다. + 새 집합이 만들어졌다면, 공간을 할당하기 위해 세마퍼의 갯수와 마찬가지로 키값이 넘겨져야 한다. + 이장의 끝에서 표현될 예제에서, 세마퍼 집합이 존재하는지 존재하지 않는지를 + 결정하기 위한 IPC_EXCL 플래그의 사용에 주목해라 - -- NOTES -- + □ -- NOTES -- - int semctl ( int semid, int semnum, int cmd, union semun arg ); + ■ 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) @@ -1775,74 +1775,74 @@ namespace ZNsMain EPERM (EUID has no privileges for cmd in arg) ERANGE(semaphore value out of range) - semctl() Լ 3 ° μ ִ + □ semctl() 함수의 3 번째 인수가 가질 수 있는 여러 값 IPC_STAT - տ semid_ds ȸϰ, - semun union buf ƱԸƮ ּ Ѵ. + 집합에 대한 semid_ds 구조를 조회하고, + semun union안의 buf 아규먼트의 주소지에 저장한다. IPC_SET - տ semid_ds ipc_perm Ѵ. - semum union buf ƱԸƮ ´. + 집합에 대한 semid_ds 구조의 ipc_perm 멤버의 값을 지정한다. + semum union의 buf 아규먼트로 부터 값을 가져온다. IPC_RMID - Ŀη Ѵ. + 커널로 부터 집합을 제거한다. GETALL - µ ȴ. - union 迭 unsigned short integer 迭 ȴ. + 집합으로 부터 모든 세마퍼의 값을 얻는데 사용된다. + 정수값들이 union의 배열 멤버에 의해 지정된 unsigned short integer 배열에 저장된다. GETCNT - ڿ ٸ ִ μ ȯѴ. + 자원에 대해 현재 기다리고 있는 프로세스의 수를 반환한다. GETPID - semop ȣ μ PID ȯѴ. + 마지막 semop 호출을 수행한 프로세스의 PID를 반환한다. GETZCNT - 100% ڿ Ȱ ٸ ִ μ ȯѴ. + 100% 자원 활용을 위해 현재 기다리고 있는 프로세스의 수를 반환한다. SETALL - վ union 迭 ȿ Ե ĪǴ Ѵ. + 집합안의 모든 세마퍼의 값을 union의 배열 멤버안에 포함된 매칭되는 값으로 지정한다. SETVAL - վ union val Ѵ. + 집합안의 개별적인 세마퍼의 값을 union의 val 멤버의 값으로 지정한다. - arg ƱԸƮ semun Ÿ Ÿ. - Ư ü(union) linux/sem.h Ǿִ. + ■ 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 + int val; // SETVAL을 위한 값 + struct semid_ds *buf; // IPC_STAT & IPC_SET을 위한 버퍼 + ushort *array; // GETALL & SETALL를 위한 배열 + struct seminfo *__buf; // IPC_INFO를 위한 버퍼 void *__pad; }; val - SETVAL ɾ ȴ.ۿ Ѵ. + SETVAL 명령어가 수행될 때 사용된다.세마퍼에 지정될 값을 지정한다. buf - IPC_STAT/IPC_SET ȴ. - Ŀξȿ Ǵ ڷ 纻 Ÿ. + IPC_STAT/IPC_SET에서 사용된다. + 커널안에서 사용되는 내부 세마퍼 자료 구조의 복사본을 나타낸다. array - GETALL/SETALL ɾ Ǵ . - վȿ ȸϰų ϴµ Ǵ - 迭 Ű ־ Ѵ. - ִ ƱԸƮ _buf _pad Ŀ ڵ峻 - Ǹ α׷ ڿԴ . - ǻ, ̷ ΰ ƱԸƮ ü Ǹ - ٸ н ã . - ̷ Ư ý ȣ ý V IPC ȣ ϴµ - Ƿ, ̷ پ ˻ ̴. + GETALL/SETALL 명령어에서 사용되는 포인터. + 집합안에서 모든 세마퍼 값들을 조회하거나 지정하는데 사용되는 + 정수값들의 배열을 가리키고 있어야 한다. + 남아있는 아규먼트인 _buf와 _pad는 커널 안의 세마퍼 코드내에서 + 내부적으로 사용되며 응용프로그램 개발자에게는 거의 쓸모가 없다. + 사실상, 이런 두개의 아규먼트는 리눅스 운영체제에서 지정되며 + 다른 유닉스 구현에서는 찾을 수 없다. + 이런 특별한 시스템 호출을 모든 시스템 V IPC 호출을 이해하는데 + 가장 어려운 점으로 꼽을 수 있으므로,실제로 이러한 다양한 예를 검사할 것이다. - ƱԸƮ(union) GETVAL ɾ õȴ. + 마지막 아규먼트(union)은 GETVAL 명령어가 사용될 때 무시된다. - Posix Semaphore unistd.h Ͽ _POSIX_SEMAPHORES ɼ - ǵǾ ִ. + ■ Posix 형 Semaphore 는 unistd.h 헤더 파일에 _POSIX_SEMAPHORES 옵션이 + 정의되었으면 사용할 수 있다. - -- POSIX() 带 ̿ α׷ (2011-05-23 20:31:00) + -- POSIX(포직스) 쓰레드를 이용한 프로그래밍 (2011-05-23 20:31:00) //////////////////////////////////////////////////////////////////////////////////*/ @@ -1859,8 +1859,8 @@ namespace ZNsMain }/* ZCProcessSemaphore()*/ - // Linux  迭 - // ϳ 迭 Ѵ. + // Linux 에서는 세마포어를 배열로 선언할 수 있으나 + // 거의 쓸 일이 없고 원소 하나의 배열로 사용한다. bool Make(const char* AP_SemaName, long AL_InitialCnt, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) { @@ -1885,7 +1885,7 @@ namespace ZNsMain 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) { @@ -1894,7 +1894,7 @@ namespace ZNsMain bool Make(int AL_InitialCnt=1, int AI_Flag=IPC_CREAT | IPC_EXCL | 0664)*/ - // ȣ  . + // 비신호상태의 세마포어를 만든다. bool MakeZero(int AI_Flag=IPC_CREAT | IPC_EXCL | 0664) { @@ -1926,8 +1926,8 @@ namespace ZNsMain union semun SemUnion; SemUnion.val=AL_InitialCnt; - // ʱȭ SETALL ɼ ص Ǵµ SemUnion.array 迭 Ҵϰ - // ʱȭϰ ϴ ϸ ׳ for ε . + // 초기화는 SETALL 옵션을 사용해도 되는데 SemUnion.array 에 배열을 할당하고 + // 초기화하고 대입하는 과정을 생각하면 그냥 for 문으로도 상관없을 것 같다. __for0(ZTypInt, i, AI_SemaCnt) { @@ -1946,8 +1946,8 @@ namespace ZNsMain 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() 는 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) { @@ -1962,7 +1962,7 @@ namespace ZNsMain bool Open(const char* AP_SemaName)*/ - // ´. + // 현재 세마포어의 값을 가져온다. int GetValue(int AI_SemaNum=0) { @@ -1989,13 +1989,13 @@ namespace ZNsMain bool Lock(ZTypUInt AI_ReleaseCount=1)*/ - // LockRaw() ̸ ZEThread_OK, ð ʰ ZEThread_TimeOut ȯѴ. - // Posix  . + // LockRaw() 는 성공이면 ZEThread_OK, 시간 초과는 ZEThread_TimeOut 을 반환한다. + // 리눅스의 Posix 세마포어에서도 같다. int LockRaw(ZTypUInt AI_ReleaseCount=1) { - // cf) Window ReleaseSemaphore(mh_Semaphore,lReleaseCount,lpPreviousCount) - // ι° μ AI_ReleaseCount Ѵ. + // cf) Window 의 ReleaseSemaphore(mh_Semaphore,lReleaseCount,lpPreviousCount) 에서 + // 두번째 인수의 역할을 AI_ReleaseCount 가 한다. struct sembuf sem_b; @@ -2009,8 +2009,8 @@ namespace ZNsMain bool UnLock(ZTypUInt AI_ReleaseCount=1) { - // cf) Window ReleaseSemaphore(mh_Semaphore,lReleaseCount,lpPreviousCount) - // ι° μ AI_ReleaseCount Ѵ. + // cf) Window 의 ReleaseSemaphore(mh_Semaphore,lReleaseCount,lpPreviousCount) 에서 + // 두번째 인수의 역할을 AI_ReleaseCount 가 한다. struct sembuf sem_b; @@ -2183,10 +2183,10 @@ namespace ZNsMain /*////////////////////////////////////////////////////////// - class ZCThreadSemaphore ȣȯDZ ƴ. - ȣȯ class ZCProcessSemaphore ణ . + ■ class ZCThreadSemaphore 는 윈도우와 상당히 호환되기 어렵다. + 윈도우와 호환은 class ZCProcessSemaphore 이 약간 좋다. - sem_t 0 . + ■ sem_t 에는 0 을 대입할 수 없다. //////////////////////////////////////////////////////////*/ @@ -2198,14 +2198,14 @@ namespace ZNsMain /*///////////////////////////////////////////////////////////////////////////// - sem_init() Լ ̸  鶧 Ѵ. ̸ִ - sem_open() ؾ ϸ, ı sem_close() sem_unlink() - ؾ Ѵ. Ŭ ̸  ٷ. + ■ sem_init() 함수는 이름없는 세마포어를 만들때 사용한다. 이름있는 세마포어의 + 경우 sem_open() 을 사용해야 하며, 파괴할 때도 sem_close() 와 sem_unlink() 를 + 사용해야 한다. 이 클래스에서는 이름없는 세마포어만 다룬다. - AI_Shared 0 ƴϸ μ Linux - sem_XXX 迭 Լ ʰ ִ.(2004.7.12) + AI_Shared 가 0 이 아니면 다중 프로세스에서도 사용할 수 있으나 현재 Linux 의 + sem_XXX 계열의 함수는 이 기능을 지원하지 않고 있다.(2004.7.12) - AI_InitValue==1 ̶ ؽó Ϸ ̴. 2007-09-30 14:32:00 + ■ AI_InitValue==1 이라면 뮤텍스처럼 사용하려는 경우이다. 2007-09-30 14:32:00 /////////////////////////////////////////////////////////////////////////////*/ @@ -2239,7 +2239,7 @@ namespace ZNsMain int LockRaw(const struct timespec& AR_TimeOut) { - // timeout ̸ errno ZNsEnum::ZEThread_TimeOut + // timeout 이면 errno 가 ZNsEnum::ZEThread_TimeOut if(::sem_timedwait(&mh_Semaphore, &AR_TimeOut)!=ZNsEnum::ZEThread_OK) return errno; @@ -2268,8 +2268,8 @@ namespace ZNsMain #endif //__USE_XOPEN2K - // sem_trywait() ̹ lock ɷ -1 - // ȯϰ, errno EAGAIN õȴ. + // sem_trywait() 은 이미 lock 이 걸려 있으면 -1 을 + // 반환하고, errno 가 EAGAIN 으로 셋팅된다. bool TryLock() { @@ -2284,8 +2284,8 @@ namespace ZNsMain bool UnLock()*/ - // sem_destroy() Լ ̸ ſ Ǵ Լ. - // ̸ִ  쿡 ǵǾ ʴ. + // sem_destroy() 함수는 이름없는 세마포어의 제거에만 사용되는 함수다. + // 이름있는 세마포어에 사용할 경우에 그 행위는 정의되어 있지 않다. bool Close() { @@ -2308,7 +2308,7 @@ namespace ZNsMain - // ؽ ؼ . + // 리눅스 쓰레드 뮤텍스는 복사해서 사용할 수 없다. class ZCThreadMutex { @@ -2371,7 +2371,7 @@ namespace ZNsMain bool Lock(long AL_MiliSec)*/ - // cf) 30 ʰ LOCK + // cf) 30 초간 LOCK // // struct timespec ts_timeout; // ts_timeout.tv_sec =time(NULL)+30; @@ -2467,8 +2467,8 @@ namespace ZNsMain bool Make(int AI_ThreadType=PTHREAD_MUTEX_RECURSIVE) { - // PTHREAD_MUTEX_RECURSIVE mutex 忡 ŭ ؾѴ. - // Ŭ ڿ ϰ Ҹڿ ϱ⿡ . + // PTHREAD_MUTEX_RECURSIVE mutex 는 같은 쓰레드에서 소유한 만큼 해제해야한다. + // 따라서 클래스 생성자에서 소유하고 소멸자에서 해제하기에 딱 좋다. if(pthread_mutexattr_init(&mo_PThreadMutexAttr)!=0) return false; @@ -2484,8 +2484,8 @@ namespace ZNsMain return false; //endif - ѵ, Mutex μ ̿ ǰ ϰ ʹٸ PTHREAD_PROCESS_SHARED - ⺻ ϴ ´. + 도 가능한데, Mutex 를 프로세스 사이에 공유되게 하고 싶다면 PTHREAD_PROCESS_SHARED + 을 기본값으로 하는 것이 맞다. -- 2010-01-04 11:59:00 @@ -2524,7 +2524,7 @@ namespace ZNsMain int LockRaw()*/ - // cf) 30 ʰ LOCK + // cf) 30 초간 LOCK // // struct timespec ts_timeout; // ts_timeout.tv_sec=time(NULL)+30; @@ -2600,16 +2600,16 @@ namespace ZNsMain /*/////////////////////////////////////////////////////////////////////////////////////////////////////////// - Ʒ + ■ 아래 선언 ZCThreadMutexEasy(const ZCThreadMutexEasy& rhs) : ZCThreadMutex() - ZCThreadMutex() g++ 4.4.6 -W ɼ ָ, Ʒ ޽ ִ. + 에서 ZCThreadMutex() 를 빼면 g++ 4.4.6 에서 -W 옵션을 주면, 아래 경고 메시지를 볼 수 있다. warning: base class 'class std::ZCThreadMutex' should be explicitly initialized in the copy constructor - ޽ ո̶ Ǵ , Ϸ Ŭ ZCThreadMutex(rhs) ȣ - ̶ ߱ ̴. + 위 경고 메시지가 합리적이라고 생각되는 것이, 컴파일러는 기초 클래스의 복사 생성자 ZCThreadMutex(rhs) 을 호출 + 할 것이라고 예상했기 때문일 것이다. -- 2013-05-05 06:49:00 @@ -2673,16 +2673,16 @@ namespace ZNsMain /*/////////////////////////////////////////////////////////////////////////////////////////////////////////// - Ʒ + ■ 아래 선언 ZCThreadMutexAttrEasy(const ZCThreadMutexAttrEasy&) : ZCThreadMutexAttr() - ZCThreadMutex() g++ 4.4.6 -W ɼ ָ, Ʒ ޽ ִ. + 에서 ZCThreadMutex() 를 빼면 g++ 4.4.6 에서 -W 옵션을 주면, 아래 경고 메시지를 볼 수 있다. warning: base class 'class std::ZCThreadMutexAttr' should be explicitly initialized in the copy constructor - ޽ ո̶ Ǵ , Ϸ Ŭ ZCThreadMutexAttr(rhs) - ȣ ̶ ߱ ̴. + 위 경고 메시지가 합리적이라고 생각되는 것이, 컴파일러는 기초 클래스의 복사 생성자 ZCThreadMutexAttr(rhs) 을 + 호출할 것이라고 예상했기 때문일 것이다. -- 2013-05-05 06:49:00 @@ -2727,35 +2727,35 @@ namespace ZNsMain /*///////////////////////////////////////////////////////// - Ʒ ⺻ ؽ ZCThreadMutexEasy - (׽Ʈ dead lock ߻Ѵ) ټ - ϴ.(Window Mutex ؼ) + ■ 아래 기본 뮤텍스 ZCThreadMutexEasy 은 재귀적으로 사용할 + 수 없어서(테스트해 보면 dead lock 이 발생한다) 다소 불 + 안하다.(Window Mutex 에 비해서) typedef ZCThreadMutexEasy ZCDefLockEasy; - ׷ Ʒ ٲ۴. -- 2009-07-28 16:27:00 + 그래서 아래 선언으로 바꾼다. -- 2009-07-28 16:27:00 - Mutex ϴ Ȳ ƾ Ѵ. + 재귀적으로 Mutex 를 사용하는 상황을 만들지 말아야 한다. -- 2013-07-22 12:28:00 - freebsd 8.2 ׽Ʈ , ڲ + ■ freebsd 8.2 에서 테스트할 때, 자꾸 pthread_mutexattr_setpshared( &mo_PThreadMutexAttr,PTHREAD_PROCESS_SHARED )!=0 - Ǵ ־, ZCThreadMutexEasy - . ׷ __MUTEX_EASY_DEFAULT_LOCK__ ǵǾ - , + 가 되는 현상이 있어서, ZCThreadMutexEasy 를 사용할 수 없 + 었다. 그래서 __MUTEX_EASY_DEFAULT_LOCK__ 가 정의되어 있 + 으면, typedef ZCThreadMutexEasy ZCDefLockEasy; - ϰ Ѵ. -- 2011-05-19 22:00:00 + 선언을 사용하게 한다. -- 2011-05-19 22:00:00 - ⺻ ZCThreadMutexEasy ϰ ZCThreadMutexAttrEasy - __MUTEX_ATTR_EASY_DEFAULT_LOCK__ ǵǾ , - ϴ Ѵ. -- 2015-09-02 21:05:00 + 기본적으로 ZCThreadMutexEasy 을 사용하고 ZCThreadMutexAttrEasy + 은 __MUTEX_ATTR_EASY_DEFAULT_LOCK__ 이 정의되어 있을 때, + 사용하는 것으로 한다. -- 2015-09-02 21:05:00 /////////////////////////////////////////////////////////*/ @@ -2770,18 +2770,18 @@ namespace ZNsMain /*/////////////////////////////////////////////////////////////////////// - spin lock ª ð ȭ . ׷ Ϲ ȭ - ؽ . spin lock context switching δ Ǿ - ĩ ӵ ִ. ʾ ɷ ϴ - ߻Ѵ. + ■ spin lock 은 짧은 시간 동기화에는 가장 좋다. 그런데 일반적으로 동기화 + 에 뮤텍스를 사용하자. spin lock 은 context switching 에 부담이 되어서 + 자칫 반응속도가 느려질 수 있다. 심지어 몇 초씩 걸러서 사용못하는 경우 + 도 발생한다. - ؽ ƴ spin lock ȭ ϴ 쿡 ȭ - ª ð Ѵ. ȭ ֿܼ ϴ ' - ó' ڴ. Ƽ 忡 spin lock ȭ - , ټ ' ó' , ۾ 尡 ؽƮ Ī - ϸ鼭 ȭ ְ ٸ ۾ - ȭ cpu spin ϰ ִٸ ȭ ʾ, - dead lock ִ. + ■ 뮤텍스가 아닌 spin lock 으로 동기화를 하는 경우에는 동기화 영역이 정말 + 짧은 수행시간을 가져야 한다. 동기화 영역에서 콘솔에 출력하는 등의 '긴 + 처리'가 있으면 아주 나쁘다. 멀티 쓰레드에서 spin lock 으로 동기화를 할 + 때, 위와 같은 다소 '긴 처리'를 할 경우, 작업 쓰레드가 컨텍스트 스위칭 + 을 하면서 동기화 영역이 끝나지 않을 수 있고 또 다른 작업 쓰레드의 동기 + 화 영역에서 cpu 가 spin 하고 있다면 동기화가 끝나는 시점이 늦어지고, + 심지어는 dead lock 에 빠질 수도 있다. -- 2008-03-20 11:27:00 @@ -2795,8 +2795,8 @@ namespace ZNsMain int Init(int AI_ShareMode=PTHREAD_PROCESS_PRIVATE) { - // μ spin lock Ѵٸ PTHREAD_PROCESS_SHARED ش. - // ׸ pthread_spinlock_t ޸𸮿 ־ Ѵ. ϴ. + // 프로세스간에 spin lock 을 공유한다면 PTHREAD_PROCESS_SHARED 를 준다. + // 그리고 pthread_spinlock_t 도 공유메모리에 있어야 한다. 절차가 복잡하다. return pthread_spin_init(&mh_SpinLock,AI_ShareMode); }/* @@ -2842,8 +2842,8 @@ namespace ZNsMain public: /*####################################################################### - Ҹڸ Լ throw(ZtCExceptBase) - ٿµ, g++ 7.3.0 . + ■ 소멸자를 제외한 각 멤버 함수 선언에 throw(ZtCExceptBase) 을 + 붙였는데, g++ 7.3.0 에서 경고가 나서 지웠다. CProcess_Linux.H:2429:25: warning: dynamic exception specifications are deprecated in C++11 [-Wdeprecated] @@ -2928,17 +2928,17 @@ namespace ZNsMain /*//////////////////////////////////////////////// - class ZtCAutoKey<> : Lock ϰ Ѵ. + ■ class ZtCAutoKey<> : Lock 을 설정하고 해제한다. - ִ Key Ͽ. + 열고 닫을 수 있는 열쇠와 같아 Key 라고 하였다. -- - ̷ RAII + 이런 식의 기법을 RAII Resource Acquisition Is Initialization - Ѵٴ ˾Ҵ. -- 2015-03-10 15:08:00 + 라고 한다는 것을 알았다. -- 2015-03-10 15:08:00 ////////////////////////////////////////////////*/ @@ -2963,7 +2963,7 @@ namespace ZNsMain ZtCAutoKey(TCriticSectEasy& AR_SyncEasy):mr_SyncEasy(AR_SyncEasy) { #ifdef _DEBUG_CAUTOKEY_ - cout<<" ZtCAutoKey:: ZtCAutoKey() "< ZtCAutoKey<> ڿ μ ޾Ƽ - ڿ Lock ϰ, Ҹڿ ٽ Lock ɾ ش. - ׷ ̷ ؾ Ȳ ü . ϴ - Dead Lock ¿ . + ■ ZtCAutoKeyRev<> 는 ZtCAutoKey<> 을 생성자에서 인수로 받아서 생 + 성자에서 Lock 을 해제하고, 소멸자에서 다시 Lock 을 걸어 준다. + 그런데 이렇게 해야 될 상황 자체를 만들지 말자. 억지로 사용하다 + 보면 자주 Dead Lock 상태에 빠진다. - 2008-04-09 21:01:00 + ※ 2008-04-09 21:01:00 ////////////////////////////////////////////////////////////////*/ @@ -3031,8 +3031,8 @@ namespace ZNsMain class ZCSpinLockProcess { public : - enum{EReturn_ShareMemNone = -2}; // ش ޸ - enum{EReturn_ShareMemMapErr= -3}; // ޸ Map + enum{EReturn_ShareMemNone = -2}; // 해당 공유메모리 없음 + enum{EReturn_ShareMemMapErr= -3}; // 공유메모리 Map 실패 private: pthread_spinlock_t* mph_SpinLock ; @@ -3119,34 +3119,34 @@ namespace ZNsMain /*////////////////////////////////////////////////////////////////////////////////////// - http://blog.naver.com/kimsk99?Redirect=Log&logNo=50004383787 + ■ http://blog.naver.com/kimsk99?Redirect=Log&logNo=50004383787 - α׷ ϸ鼭 带 , CreateThread _beginthread Լ -  Լ ؾ ϰ ȴ. ׻ ⺻ API CreateThread - Ծ. ׷ å дٰ װ ߸Ǿٴ ˾Ҵ. MSDN - ڼ о ̾ ڼ ׵ - . ϴ CreateThread SDK ϴ ⺻ API̴. Ư ̺귯 - ũ ʾƵ ϵǰ ư. + 윈도우 프로그램을 하면서 쓰레드를 생성할 때, CreateThread와 _beginthread라는 두 함수 + 중 어떤 함수를 사용해야 할 지 고민하게 된다. 난 항상 뭔가 기본 API같은 CreateThread + 를 사용해 왔었다. 그런데 오늘 책을 읽다가 그게 잘못되었다는 것을 알았다. MSDN 에 나 + 온 설명을 자세히 읽어보면 나오는 내용이었지만 보통 자세히는 안 읽으니 그동안 몰랐 + 었다. 일단 CreateThread 는 윈도우 SDK에서 제공하는 기본 API이다. 특별한 라이브러리와 + 링크하지 않아도 윈도우라면 컴파일되고 돌아간다. 하지만 - _beginthread(Ǵ _beginthreadex) + _beginthread(또는 _beginthreadex) - standard C library Լ ũؾ Ѵ. ׷ ɿ - . ɿ ̰ ʴ´ٸ ̷ ̴. + 는 standard C library에 속한 함수로 링크해야 동작한다. 그렇기 때문에 기능에서도 차이 + 가 난다. 사실 기능에서 차이가 나지 않는다면 이렇게 구별할 이유가 없었을 것이다. - _beginthread ޶ ʿ - 찡 ִ. ׷ Լ _beginthreadex CreateThread - ڸ ִ. ׷ CreateThread _beginthreadex ġ - ȯ ϴ. + _beginthread 와 같은 경우 인자의 종류가 달라서 쓰레드 생성시 필요한 설정을 할 수 없 + 는 경우가 있다. 그러나 비슷한 함수인 _beginthreadex 는 완전히 CreateThread와 같은 + 인자를 가지고 있다. 그렇기 때문에 CreateThread가 쓰인 모든 곳은 _beginthreadex로 치 + 환이 가능하다. - εۿ ū _beginthread standard C library ϴ - TLB ʱȭ شٴ ̴. standary C library ִ Լ Ϻδ thread- - safety ؼ TLB ϴµ ʱȭ ʴ´ٸ ߻ ִ. + 내부동작에서 가장 큰 차이점은 _beginthread 는 standard C library에서 사용하는 영역에 + 대한 TLB 초기화를 해준다는 것이다. standary C library에 있는 함수 중 일부는 thread- + safety를 위해서 TLB 를 사용하는데 초기화가 되지 않는다면 문제가 발생할 수 있다. - _beginthreadex Լ ؼ 带 ߴٸ Լ 带 - ϱ ؼ ExitThread Լ ϱ ٴ _endthreadex Լ ϱ Ѵ. + _beginthreadex 함수를 사용해서 쓰레드를 구동했다면 스레드 함수 내에서 쓰레드를 종료 + 하기 위해서 ExitThread 함수를 사용하기 보다는 _endthreadex 함수를 사용하길 권장한다. - κ C library ϱ _beginthreadex ؾ - Ѵ. + 대부분의 경우 C library를 사용하기 때문에 쓰레드의 생성은 _beginthreadex 를 사용해야 + 한다. uintptr_t _beginthreadex ( @@ -3168,7 +3168,7 @@ namespace ZNsMain LPDWORD lpThreadId ); - CreateThread _beginthreadex ü ְ ׷ Ѵ. + CreateThread 는 _beginthreadex 로 대체될 수 있고 그래야 한다. dwCreationFlags [in] Flags that control the creation of the thread. @@ -3192,7 +3192,7 @@ namespace ZNsMain cf) DWORD ResumeThread( HANDLE hThread ); - IN WINBASE.H + ■ IN WINBASE.H typedef DWORD (WINAPI *PTHREAD_START_ROUTINE) ( @@ -3208,37 +3208,37 @@ namespace ZNsMain typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; - LPTHREAD_START_ROUTINE AP_StartAddress Լ - DWORD WINAPI ThreadFunc(LPVOID lpRarameter) + LPTHREAD_START_ROUTINE AP_StartAddress 는 시작함수포인터 + 원형은 DWORD WINAPI ThreadFunc(LPVOID lpRarameter) - MFC ȭ object + ■ MFC 의 동기화 object - Ʒ object ؼ ʿ + 아래 object 를 쓰기 위해서는 가 필요 1) CCriticalSection cs; cs.Lock(); - // ۾ڵ + // 작업코드 cs.Unlock(); 2) CEvent event; - Thread ֵ Ǵ - CEvent object ϰ Thread CallBack Լ + Thread 들이 참조할 수 있도록 전역 또는 상위 블럭에 + CEvent object 를 선언하고 Thread CallBack 함수에서 UINT ThreadFunc(LPVOID pParam) { while(TRUE) { - CEventOvj.Lock(); // ̵. + CEventOvj.Lock(); // 잠이든다. - // ̺Ʈ ߻ ڵ带 ´. - // ׸ ܺο - // CEventOvj.PulseEvent(); ̳ - // CEventOvj.SetEvent(); ȣϸ . + // 이벤트가 발생할 때 실행될 코드를 적는다. + // 그리고 외부에서 + // CEventOvj.PulseEvent(); 이나 + // CEventOvj.SetEvent(); 를 호출하면 깨어난다. - // Thread Lock ɷ ¿ - // PulseEvent Լ ȣϸ ƹϵ Ͼ ʰ - // ٷ Lock() ȣϸ ٽ ܴ. - // SetEvent() 쿡 ׳ Ѵ. + // Thread 가 Lock 이 걸려 있지 않은 상태에서 + // PulseEvent 함수를 먼저 호출하면 아무일도 일어나지 않고 + // 바로 다음 순간에 Lock() 를 호출하면 다시 잠을 잔다. + // SetEvent() 의 경우에는 그냥 통과한다. } //while(TRUE) } @@ -3255,7 +3255,7 @@ namespace ZNsMain void* ThreadFunc()(void*) - -- MFC ȭ object + ■ -- MFC 의 동기화 object //////////////////////////////////////////////////////////////////////////////////////*/ @@ -3356,7 +3356,7 @@ namespace ZNsMain /*//////////////////////////////////////////////////////////// - pthread_attr_setschedpolicy() 2 μ 밡 + ■ pthread_attr_setschedpolicy() 의 2 번 인수에 사용가능한 값 SCHED_FIFO First in-first out (FIFO) scheduling policy. @@ -3397,7 +3397,7 @@ namespace ZNsMain int SetStackSize(size_t AI_StackSize) { - // PTHREAD_STACK_MIN ̻̾ Ѵ. + // PTHREAD_STACK_MIN 이상이어야 한다. return pthread_attr_setstacksize(&mh_ThreadAttr, AI_StackSize); }/* @@ -3405,31 +3405,31 @@ namespace ZNsMain /*///////////////////////////////////////////////////////////////////////// - ̺ R. Ʈ 'POSIX 带 ̿ α׷' 200 page + ■ 데이비드 R. 부트노프 저 'POSIX 쓰레드를 이용한 프로그래밍' 200 page 에 - ýۿ _POSIX_THREAD_ATTR_STACKSIZE ȣ ϰ ִٸ, - size_t statcksize Ӽ ִ. + 시스템에서 _POSIX_THREAD_ATTR_STACKSIZE 기호 상수를 정의하고 있다면, + size_t statcksize 속성을 사용할 수 있다. - Ǿ ִµ, CentOS 64 bit + 고 되어 있는데, 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 + 을 찾을 수 있다. -- 2011-05-23 20:44:00 - å, + ■ 역시 같은 책, 같은 페이지에 - POSIX 忡 忡 䱸ϴ ּ ũ⸦ Ÿ - ȣ μ PTHREAD_STACK_MIN Ѵ. + POSIX 쓰레드에서는 한 쓰레드에서 요구하는 스택의 최소 크기를 나타내는 + 기호 상수로서 PTHREAD_STACK_MIN 을 정의한다. - ȣ CentOS ã bits/local_lim.h + 이 기호를 CentOS 에서 찾으면 bits/local_lim.h 에 #define PTHREAD_STACK_MIN 16384 - Ǿ ִ. -- 2011-05-23 20:55:00 + 라고 되어 있다. -- 2011-05-23 20:55:00 /////////////////////////////////////////////////////////////////////////*/ @@ -3501,7 +3501,7 @@ namespace ZNsMain bool Make(void* AP_StartAddress(void*), void* AP_Arg=NULL, pthread_attr_t* AP_ThreadAttr=NULL)*/ - // ñ Լ ()Ų. + // 쓰레드 종료시까지 메인 함수의 실행을 지연(블럭)시킨다. bool Wait() { @@ -3524,15 +3524,15 @@ namespace ZNsMain /*//////////////////////////////////////////////////////////////////////////////////// - pthread_detach μ fork() Ŀ waitpid() ʾƵ ǵ - SIGCHILD ϴ Ͱ ϴ. + ■ pthread_detach 는 프로세스에서 fork() 후에 waitpid() 를 하지 않아도 되도록 + SIGCHILD 를 무시하는 것과 동일하다. - ׸ (::pthread_join) Ÿ, ݵ ȣؾ ϴ . - pthread_detach() ȣ 尡 ߴµ ޸𸮰 OS ȯ - ִ. www.wordncode.com ϼ ڵ带 Ծϸ - Ŭ̾Ʈ ߴµ ޸𸮰 پ ʰ ϴ ̾. ׷ - ()޸𸮸 Ͽ Ŭ̾Ʈ ӽÿ ؼ 带 - ϰ ־! + 그리고 병합(::pthread_join) 하지 않을 거면, 반드시 호출해야 하는 것으로 기억하자. + pthread_detach() 을 호출하지 않으면 쓰레드가 종료했는데도 메모리가 OS 에 반환되지 + 않을 수 있다. www.wordncode.com 의 파일서버를 만들어 줄 때 이 코드를 빼먹었더니만 + 클라이언트가 종료했는데도 계속 메모리가 줄어들지 않고 증가만 하는 것이었다. 그래서 + 어느 시점에 (가상)메모리를 소진하여 클라이언트 접속시에 컨넥션 쓰레드를 만들지 못 + 하고 있었다! -- 2009-02-24 03:08:00 @@ -3553,20 +3553,20 @@ namespace ZNsMain /*////////////////////////////////////////////////////////////////////////////// - 带 (pthread_cancel)Ѵٴ ٸ κ ҿû ޾Ƽ - ۵ ϴ ǹմϴ. ġ kill ̿ؼ μ ߴܽŰ - Ͱ մϴ. ׷ ߴ û 尡 ٷ ߴܵǴ°? װ ƴ - ϴ. kill μ ̴ ͵ δ μ ̴ ñ׳ - μ ñ׳ óϿ ׾ ϴµ - ְų Ȥ (deferred) Ǿ ״ 쵵 ߻մϴ. ҵ ̿ - ٷ ׾ ʽϴ. ҵǵ ϴٸ, - ⺻ (deferred) Ҹ ǹմϴ. + ■ 쓰레드를 취소(pthread_cancel)한다는 것은 다른 쓰레드로부터 취소요청을 받아서 + 작동을 중지하는 것을 의미합니다. 마치 kill 을 이용해서 프로세스를 중단시키는 + 것과 비슷합니다. 그러나 중단을 요청받은 쓰레드가 바로 중단되는가? 그것은 아닙 + 니다. kill 로 프로세스를 죽이는 것도 실제로는 프로세스를 죽이는 시그널을 보내 + 고 그 다음은 프로세스가 시그널을 처리하여 죽어줘야 하는데 가끔 죽지 않을 수도 + 있거나 혹은 지연(deferred) 되어 죽는 경우도 발생합니다. 쓰레드의 취소도 이와 + 같이 바로 죽어주지는 않습니다. 물론 즉시 취소되도록 설정할 수도 있읍니다만, + 쓰레드 취소의 기본 세팅은 지연된(deferred) 취소를 의미합니다. - ý Ʈũ α׷ : ǻ : 輱 315 page + 리눅스 시스템 네트워크 프로그래밍 : 가메출판사 : 김선영 저 315 page - cf) int pthread_setcancelstate(int state,int* oldstate) : Լ + ■ cf) int pthread_setcancelstate(int state,int* oldstate) : 원자적 함수 - state PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DISABLE + state 은 PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DISABLE 중의 한 값 //////////////////////////////////////////////////////////////////////////////*/ @@ -3686,83 +3686,83 @@ namespace ZNsMain /*////////////////////////////////////////////////////////////////////////////////////// - class ZtCMutexCond window ؽ Ǻ Ŭ + ■ class ZtCMutexCond 는 window 에는 없는 리눅스 뮤텍스 조건변수 클래스 - ̰ ټ 尡 Լ A, Լ B, Լ C ϴµ, ݵ - A -> B -> C ؾ ϰ Լ ȭ ־ , - Ǻ ϸ ؽ ϳ (Ǻ 3-1 ), ؽθ Ѵٸ A, - B,C 3 ؽ ؾ Ѵ. ؽ - ִ. ݴ Ǻ ؽ . + 이것이 유용한 경우는 다수의 쓰레드가 함수 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 ϴ - ۾ · ϴ ̷ Ѵ. ̷ ٸ 尡 - ǰ ִ 带 Ȯϰ Ǻ ְԲ ش. ̰ - ̴. + ■ 어떤 작업 큐에 다수의 쓰레드가 접근하여 작업을 가져온다고 가정하자. 작업큐에 접근하는 + 쓰레드는, 큐에 접근하는 동안은 다른 쓰레드가 동시 접근하지 않도록 '작업 큐 접근 동기 + 화 object ' 에 lock 을 걸고 해당 큐가 비어있는지 그렇지 않은지를 조사할 것이다. 이때 + 큐에 등록된 작업이 하나라도 있다면 그 작업을 가져오고 '작업큐 접근 동기화 object' 를 + unlock 할 것이다. 만일 큐에 등록된 작업이 없다면 '작업 큐 접근 동기화 object' 를 unlock + 하고 자신은 작업큐에 작업이 등록될 때까지 블럭되어야 한다. 이때 자신이 블럭되고 있다 + 는 것을 알리는 표시를 하고(그래야 나중에 '깨울' 수 있으니까) 블럭되야 하는데, 이 사이 + 에 즉 unlock 과 블럭표시를 하고 블럭되는 사이에 다른 쓰레드가 끼어들어 '작업큐 접근 + 동기화 object' 에 lock 을 걸고 작업을 등록하면, 작업은 분명 있는데 블럭표시를 하려는 + 쓰레드는 블럭표시를 하기도 전이므로, 다른 쓰레드는 그 쓰레드가 블럭되고 있지 않다고 + 보고 별 처리없이 '작업큐 접근 동기화 object' 에 unlock 을 하고 다음을 진행할 것이다. + 그러면 블럭표시를하고 블럭되려는 쓰레드는 블럭이 해제될 기회를 갖지 못한 채 영원히 블 + 럭될 수 있다. 이 사태를 방자하기 위해 '작업큐 접근 동기화 object' 에 unlock 을 하는 + 작업과 블럭상태로 진입하는 명령은 원자적으로 이루어져야 한다. 이러면 다른 쓰레드가 블 + 럭되고 있는 쓰레드를 정확하게 판별할 수 있게끔 보장해준다. 이것이 조건 변수가 존재하 + 는 이유이다. - ׻ ؽ ä ؾ Ѵ. - ( ϱ , ϰ ؽ ´.) + 조건 변수 대기는 항상 뮤텍스를 잠근 채로 리턴해야 한다. + (물론 리턴하기 전, 대기하고 있을 동안은 뮤텍스를 잠그지 않은 상태다.) - ؽ ä 󸶵 Ǻ ñ׳ ų εijƮ - .  尡 Ǻ ñ׳ ų εijƮѴ - 尡 ϳ ٸ ƹϵ Ͼ ʴ´. ٸ - pthread_cond_wait() Լ ȣѴٸ, ٷ ش ñ׳ - ٴ ϰ ٸ ۿ . ٷ - ȵǴ Ȳ̶  ȴ. 尡 Ǻ - ؽ ä ֱ , ˻ ⵵߿(ٸ 鿡 - )  . ؽ Ƿ ٸ - Ÿ ̴. + ■ 뮤텍스를 잠그지 않은 채로 얼마든지 조건변수로 시그널을 보내거나 브로드캐스트 할 수 있 + 다. 어떤 쓰레드가 조건변수로 시그널을 보내거나 브로드캐스트한다 할지라도 대상 조건 변 + 수에서 대기 중인 쓰레드가 하나도 없다면 아무일도 일어나지 않는다. 잠시 후 다른 쓰레드 + 가 pthread_cond_wait() 함수를 호출한다면, 바로 전에 해당 조건 변수로 시그널이 보내졌 + 다는 것을 알지 못하고 그저 기다리는 수밖에 없다. 따라서 이 시점이 절대로 기다려서는 + 안되는 상황이라면 쓰레드는 결코 깨어날 수 없게 된다. 쓰레드가 조건변수에서 블럭될 때 + 까지 뮤텍스는 잠긴 채로 남아 있기 때문에, 술어 검사와 대기도중에는(다른 쓰레드들에 의 + 해) 술어가 설정될 수 없다. 즉 뮤텍스가 잠겨 있으므로 다른 쓰레드들이 술어 등의 공유 + 데이타들을 변경할 수 없는 것이다. - ׻  ׽Ʈ϶! ׸ ٽ ѹ ׽Ʈ϶! + ■ 항상 술어를 테스트하라! 그리고 다시 한번 테스트하라! - 尡  , ٽ  ׽Ʈϴ ſ ߿ϴ. - ׻ ̿Ͽ ϴ . + 쓰레드가 깨어났을 때, 다시 술어를 테스트하는 것 역시 매우 중요하다. 따라서 조건 변수 + 대기는 항상 루프를 이용하여 수행하는 것이 좋다. - -- ̺ R Ʈ Posix 带 ̿ α׷ 123P + -- 데이비드 R 부트노프 저 Posix 쓰레드를 이용한 프로그래밍 123P - Ǻ Ư ؽ ǰ յǾ Ѵ. 尡 - ׻ յ ؽ װ ־ Ѵ. Ǻ - , 带 ϱ ؽ ϰ ڵ ϱ ؽ - ٽ ٴٴ + 각 조건변수는 특정 뮤텍스 및 술어 조건과 결합되어야 한다. 또한 쓰레드가 조건 변수상 + 에서 대기할 때는 항상 결합된 뮤텍스를 잠그고 있어야 한다. 조건변수 대기명령을 사용하 + 면, 쓰레드를 블록하기 전에 뮤텍스의 잠금을 해제하고 원래 코드로 리턴하기 전에 뮤텍스 + 를 다시 잠근다는 사실을 기억하자 - -- ̺ R Ʈ Posix 带 ̿ α׷ 123P + -- 데이비드 R 부트노프 저 Posix 쓰레드를 이용한 프로그래밍 123P - window ؽ ϱⰡ 絥, - Ư "" "" Ѵٸ IOCP GetQueuedCompletionStatus() - Լ ̿Ͽ ִ. + ■ window 에서는 뮤텍스 조건 변수를 구현하기가 대단히 힘든데, 만일 조건 변수의 기능을 + 특정 쓰레드의 "대기"와 "깨어남" 으로 한정한다면 IOCP 와 GetQueuedCompletionStatus() + 함수를 이용하여 구현할 수 있다. - window Ǻ ̺Ʈ ϴ . + window 에서 조건변수는 이벤트로 구현하는 것이 제일 무난한 것 같다. -- 2008-12-05 15:06:00 - غ Ǻ ߿ ù° "" ° ؽ 尡 - "ٸ 尡 ϴ " ϴ ƴұ Ѵ. + ■ 이제 생각해보니 조건변수의 중요 역할은 첫째 "대기" 와 둘째 뮤텍스를 잠근 쓰레드가 아 + 닌 "다른 쓰레드가 잠금을 해제하는 것" 을 허용하는 것이 아닐까 한다. -- 2007-11-12 07:56:00 - "۾" Ǻ ϰ ְ, "־" "۾" ñ׳ - غ. "־" "۾" ñ׳ , "۾ - " ؽ Lock ɰ Լ ÷ ̴. ̶ "־" - Lock ɰ ñ׳ ´ٸ, "۾" Լ ϱ ̹ - ؽ Ƿ, ؽ Ǯ ٽ ϰ ȴ. ñ׳ - "־" Lock Ǯ־ Ѵ. ñ׳η  "۾ - " ؽ Lock ɰ Լ ϰ Ǹ ؽ Lock Ǯ - . -- 2007-11-16 05:51:00 + ■ "작업쓰레드" 가 조건변수에서 대기하고 있고, "주쓰레드" 에서 "작업쓰레드" 에 시그널을 + 보내 깨우는 과정을 생각해보자. "주쓰레드" 에서 "작업쓰레드" 에 시그널을 보내면, "작업 + 쓰레드" 는 뮤텍스에 Lock 을 걸고 대기 함수를 빠져나올려고 할 것이다. 이때 "주쓰레드" + 에서 Lock 을 걸고 시그널을 보냈다면, "작업쓰레드" 는 대기 함수를 리턴하기 전에 이미 + 뮤텍스가 잠겨있으므로, 뮤텍스가 풀릴 때까지 다시 대기하게 된다. 따라서 시그널을 보낸 + "주쓰레드" 는 가급적 빨리 Lock 을 풀어주어야 한다. 또한 시그널로 인해 깨어난 "작업쓰 + 레드"도 뮤텍스에 Lock 을 걸고 대기 함수를 리턴하게 되면 뮤텍스의 Lock 을 빨리 풀어주 + 는 것이 좋다. -- 2007-11-16 05:51:00 //////////////////////////////////////////////////////////////////////////////////////*/ @@ -3786,14 +3786,14 @@ namespace ZNsMain /*///////////////////////////////////////////////////////// - pthread_cond_init ȯ( 0) + ■ pthread_cond_init 의 에러 반환값(성공시 0) - EAGIN (޸̿) ڿ ϴ. - ENOMEM ޸𸮰 ϴ. - EBUSY Ǻ ̹ ʱȭ Ǿ ִ. - EINVAL AP_CondAttr ùٸ ʴ. + EAGIN (메모리이외의) 자원이 부족하다. + ENOMEM 메모리가 부족하다. + EBUSY 조건변수가 이미 초기화 되어 있다. + EINVAL AP_CondAttr 이 올바르지 않다. - ̸ ʱȭ Ѵ. (PTHREAD_COND_INITIALIZER) + 가급적이면 정적초기화를 사용한다. (PTHREAD_COND_INITIALIZER) /////////////////////////////////////////////////////////*/ }/* @@ -3803,7 +3803,7 @@ namespace ZNsMain { /*//////////////////////////////////////////////////////////// - pthread_cond_destroy() + ■ pthread_cond_destroy() RETURN VALUES On success, pthread_cond_destroy() returns 0. @@ -3817,8 +3817,8 @@ namespace ZNsMain EFAULT cond is an invalid pointer - PTHREAD_COND_INITIALIZER ũθ Ͽ - ʱȭ Ǻ ı ʾƵ ȴ. + ■ PTHREAD_COND_INITIALIZER 메크로를 사용하여 + 정적으로 초기화된 조건변수는 파괴하지 않아도 된다. ////////////////////////////////////////////////////////////*/ @@ -3832,16 +3832,16 @@ namespace ZNsMain /*////////////////////////////////////////////////////////// - pthread_cond_wait Լ Ƿ ؽ ʱ - ȭǾ ְ lock Ǿ ־ Ѵ. Լ Ǹ - Լ ο ؽ lock ä - . ׸ ñ׳ Ǹ - ۾ 簳Ѵ. ش ñ׳ ߻ - μ ؽ pthread_cond_wait - Լ ϰ ȴ. pthread_cond_timedwait - Լ ϸ timespec ðŭ ⸦ ϰ - ȴ. ð ñ׳ Ÿ - ƿ ڵ Բ ȴ. + ■ pthread_cond_wait 함수가 제대로 수행되려면 뮤텍스가 초기 + 화되어 있고 lock 이 되어 있어야 한다. 이 함수가 실행되면 + 함수는 내부에 사용된 뮤텍스의 lock 을 해제한 채로 대기 작 + 업에 들어간다. 그리고 조건 변수에 대한 시그널이 검출되면 + 작업을 재개한다. 즉 해당조건 변수에 대한 시그널이 발생하 + 면 내부의 인수로 지정된 뮤텍스를 잠근후 pthread_cond_wait + 함수의 다음 라인을 실행하게 된다. pthread_cond_timedwait + 함수를 사용하면 timespec 에 지정된 시간만큼 대기를 하게 + 된다. 만약 지정된 시간내에 시그널이 검출되지 않으면 타임 + 아웃 에러코드와 함께 실행이 중지된다. //////////////////////////////////////////////////////////*/ }/* @@ -3849,7 +3849,7 @@ namespace ZNsMain int WaitCondTime(pthread_mutex_t& AR_MutexArg, struct timespec& AR_Expriation) { - // time out ̸ ZNsEnum::ZEThread_TimeOut(ETIMEDOUT) ȯѴ. + // time out 이면 ZNsEnum::ZEThread_TimeOut(ETIMEDOUT) 을 반환한다. return ::pthread_cond_timedwait(&mh_PThread_Cond, &AR_MutexArg, &AR_Expriation) ; @@ -3949,14 +3949,14 @@ namespace ZNsMain /*/////////////////////////////////////////////////////////////////////////////// - pthread_cond_broadcast() Լ ϴ 忡 ñ׳ - . 尡 Ͼ ǹǷ 밳 ߻ ɼ ִ. - ؾ ۾ 10 1 װ - ڿ ٽ Ѵ. ̷  ٽ - · ʿ 带 ߻Ű ȴ.  쿡 - εijƮ ؼ ؾ Ѵ. + ■ pthread_cond_broadcast() 함수는 조건 변수에서 대기하는 모든 쓰레드에게 시그널 + 을 보낸다. 모든 쓰레드가 일어나게 되므로 대개 경합이 발생할 가능성이 있다. 만 + 일 해야 할 작업이 10 개라면 실제로 일을 가져가는 쓰레드는 1 개일 테고 나머지는 + 조건을 비교한 뒤에 다시 대기한다. 이렇게 쓸데없이 깨어난 쓰레드들이 다시 대기 + 상태로 가는 것은 필연적으로 오버헤드를 발생시키게 된다. 따라서 어떤 경우에 브 + 로드캐스트를 쓸 것인지를 잘 생각해서 디자인해야 한다. - -- ý Ʈũ α׷, 輱 , ǻ + -- 리눅스 시스템 네트워크 프로그래밍, 김선영 저, 가메출판사 ///////////////////////////////////////////////////////////////////////////////*/ @@ -3976,9 +3976,9 @@ namespace ZNsMain /*/////////////////////////////////////////////////////////////// - mutex Ǻ Ŭ. ZtCMutexCond<> ø - ZCProcessMutex ̿ϸ ȭ ϱ - ؼ ϴ ̴. + ■ mutex 와 조건변수를 결합한 클래스다. ZtCMutexCond<> 템플릿과 + ZCProcessMutex 등을 적절히 이용하면 되지만 좀더 최적화 하기 위 + 해서 별도로 구현하는 것이다. ///////////////////////////////////////////////////////////////*/ @@ -3995,7 +3995,7 @@ namespace ZNsMain { #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; @@ -4028,7 +4028,7 @@ namespace ZNsMain }/* int UnLock()*/ - int WaitCond() // ش ؽ lock ɷ ־ Ѵ. + int WaitCond() // 해당 뮤텍스에 lock 이 걸려 있어야 한다. { return ::pthread_cond_wait(&mh_Cond, &mh_Mutex) ; }/* @@ -4050,46 +4050,46 @@ namespace ZNsMain int WaitCondTime(int AI_TimeOutMili) { - timespec VO_TimeAbs; // ð + timespec VO_TimeAbs; // 절대시간 timeval VO_TimeNow; /*/////////////////////////////////////////////////////// - timespec + ■ timespec struct timespec { __time_t tv_sec ; // Seconds. - long int tv_nsec; // Nanoseconds. 10 1 , 1 и=1000*1000 + long int tv_nsec; // Nanoseconds. 10 억분의 1 초, 1 밀리초=1000*1000 나노초 }; - int gettimeofday( struct timeval *tv, struct timezone *tz); + ■ int gettimeofday( struct timeval *tv, struct timezone *tz); int settimeofday(const struct timeval *tv,const struct timezone *tz); - -- linux manual + -- linux manual 에서 struct timeval { - long tv_sec; // - long tv_usec; // ũ + long tv_sec; // 초 + long tv_usec; // 마이크로초 }; struct timezone { - int tz_minuteswest; // ׸ġ (minutes) - int tz_dsttime; // DST Ÿ + int tz_minuteswest; // 그리니치 서측 분차(minutes) + int tz_dsttime; // DST 보정 타입 }; - timezone struct ʴ´; - tz_dsttime ʵ尡 ʴ´. - ݱ ׷ ε libc glibc ̴. - Ŀ ҽ( ̿ܿ) ʵ尡 ̴. - ׷ ̰Ÿ. + timezone struct 는 사용하지 않는다; + 리눅스에서 tz_dsttime 필드가 사용되지 않는다. + 지금까지 그렇고 앞으로도 libc 나 glibc에서 지원되지 않을 것이다. + 커널 소스에서(선언 이외에) 이 필드가 나오는 모든 경우는 버그이다. + 그래서 다음 내용은 순전히 역사적인 흥미거리다. ~~~~~~ - gettimeofday settimeofday ϸ 0 ϸ, - нÿ -1 Ѵ.(errno ȴ.) + gettimeofday와 settimeofday 모두 성공하면 0을 리턴하며, + 실패시에는 -1을 리턴한다.(errno는 적당한 값으로 설정된다.) ///////////////////////////////////////////////////////*/ @@ -4126,7 +4126,7 @@ namespace ZNsMain { #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; @@ -4152,25 +4152,25 @@ namespace ZNsMain /*////////////////////////////////////////////////////////////////// - ZtCEventCond<> ø Window event , Ư ǿ - ϴ 带 Ѳ ؼ ʿϴ. + ■ ZtCEventCond<> 템플릿은 Window 의 event 와 같이, 특정 조건에서 대 + 기하는 모든 쓰레드를 한꺼번에 깨우기 위해서 필요하다. - Linux pthread_cond_signal() Լ ش ϰ - ִ ϳ . event ȿ + Linux 의 pthread_cond_signal() 함수는 해당 조건 변수에 대기하고 + 있는 쓰레드 중 하나를 깨운다. event 효과를 낼려면 pthread_cond_broadcast() - ؾ Ѵ. + 를 사용해야 한다. - ܼ WakeCond() Լ WakeAllCond() Լ ִ. + 단순히 WakeCond() 함수를 WakeAllCond() 함수로 가리고 있다. -- 2009-10-25 23:05:00 - ټ 尡 ϰ ִµ, signal 2 ȸ - 쿡, 2 尡 ٰ - . signal 1 ȸ ߻ÿ context switching Ͼ  - 尡 , ٽ Ѵٸ, 2 ° - signal 尡  ִ ̴. + ■ 조건 변수에서 다수의 쓰레드가 대기하고 있는데, signal 을 2 회 연속 + 으로 보낸 경우에, 2 개 쓰레드가 연속적으로 깨어난다고 보장할 수 없 + 다. signal 1 회 발생시에 context switching 이 일어나서 깨어난 쓰레 + 드가 무슨 일을 한 다음에, 다시 조건 변수에서 대기한다면, 2 번째 + signal 에서 그 쓰레드가 또 깨어날 수 있는 것이다. -- 2009-10-26 13:18:00 @@ -4202,7 +4202,7 @@ namespace ZNsMain { protected: bool mb_IsValidID; - ::pthread_barrier_t mh_BarrierID; // 0 ʱȭ . + ::pthread_barrier_t mh_BarrierID; // 0 으로 초기화할 수 없다. public : ZtCBarrier() @@ -4216,11 +4216,11 @@ namespace ZNsMain /*///////////////////////////////////////////////// - Init() Fini() ϰ ٷ + ■ Init() 와 Fini() 의 리턴값을 다룰 때는 if(CBarrierObj.Init(3)==ZNsEnum::ZEBarrier_OK) - ̷ Ѵ. + 이런 식으로 한다. /////////////////////////////////////////////////*/ @@ -4280,7 +4280,7 @@ namespace ZNsMain bool Wait()*/ - // Ʒ 2 쿡 . + // 아래 2 개의 멤버는 윈도우에는 없다. bool GetShared(::pthread_barrierattr_t AH_BarrierAttr, int& ARRI_PShared) { @@ -4289,8 +4289,8 @@ namespace ZNsMain bool GetShared(::pthread_barrierattr_t AH_BarrierAttr, int& ARRI_PShared)*/ /* cf) PTHREAD_PROCESS_SHARED, PTHREAD_PROCESS_PRIVATE - AI_PShared PTHREAD_PROCESS_SHARED ϴ 쿡 - mh_BarrierID ޸𸮿 ؾ Ѵ. */ + AI_PShared 을 PTHREAD_PROCESS_SHARED 로 지정하는 경우에 + mh_BarrierID 은 공유 메모리에 존재해야 한다. */ bool SetShared(::pthread_barrierattr_t AH_BarrierAttr, int AI_PShared=PTHREAD_PROCESS_SHARED) { @@ -4327,11 +4327,11 @@ namespace ZNsMain /*////////////////////////////////////////////////// - Init() Fini() ϰ ٷ + ■ Init() 와 Fini() 의 리턴값을 다룰 때는 if(CBarrierObj.Init(3)==ZNsEnum::ZEBarrier_OK) - · Ѵ. + 의 형태로 한다. //////////////////////////////////////////////////*/ @@ -4414,15 +4414,15 @@ namespace ZNsMain /*/////////////////////////////////////////////////////// - class ZtCAtomicIntSync<> + ■ class ZtCAtomicIntSync<> - Ŀ̳ ̺귯 ȭ object ʰ - ȭ ϰ 쿡 ϴ Ŭ ø. - volatile gint ̿ϰ ִ. + 커널이나 라이브러리의 동기화 object 를 사용하지 않고 + 동기화를 구현하고 싶은 경우에 사용하는 클래스 템플릿. + volatile gint 에 대한 원자적 연산을 이용하고 있다. - lock-free . + 일종의 lock-free 다. - int sched_yield(void) : IN + ■ int sched_yield(void) : IN A process can relinquish the processor voluntarily without blocking by calling sched_yield(). @@ -4441,12 +4441,12 @@ namespace ZNsMain On success, sched_yield() returns 0. On error, -1 is returned, and errno is set appropriately. - atomic Լ Ʒ ȸ ִ. + ■ 리눅스에서 정수의 atomic 연산 함수는 아래 명령으로 조회할 수 있다. find /usr/include/ | xargs grep 'atomic' | grep 'add' # or find /usr/include/ | xargs grep 'atomic' | grep 'increment' - memory barrier ڵ Ʒ . + ■ memory barrier 관련 코드는 아래와 같다. [root@localhost ~]# find /usr/include/ | xargs grep -n 'MEM_BARRIER' | more @@ -4461,7 +4461,7 @@ namespace ZNsMain /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+ ̺귯̴.) + ■ glib 에 있는 아래 함수를 이용한다. (glib 는 gtk+ 용 라이브러리이다.) gboolean g_atomic_int_compare_and_exchange ( @@ -4476,7 +4476,7 @@ namespace ZNsMain Returns : TRUE, if *atomic was equal oldval. FALSE otherwise - Ʒ Լ Ѵ. + □ 아래 함수도 참고한다. gboolean g_atomic_pointer_compare_and_exchange ( @@ -4486,20 +4486,20 @@ namespace ZNsMain ); //gboolean g_atomic_pointer_compare_and_exchange - -- 2010-04-03 18:05:00 + ■ -- 2010-04-03 18:05:00 -  ZtCAtomicIntSync<> ȭ object ؼ - (̰) Ǵ , ZtCAtomicIntSync<>::TypeSync Ÿ ؼ -  ȭ object ߴ Ÿ ̴. + ■ 리눅스 등에서 ZtCAtomicIntSync<> 이 동기화 object 를 사용해서 + (무겁게) 구현되는 경우, ZtCAtomicIntSync<>::TypeSync 타입을 통해서 + 어떤 동기화 object 를 사용했는지를 나타낼 것이다. -- 2010-04-17 21:29:00 - alsa/iatomic.h atomic Լ ֱ ѵ, - glib g_atomic_int_compare_and_exchange() شϴ Լ . + ■ 리눅스에서는 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() Լ ִ. + ■ (리눅스 centos)alsa/iatomic.h 에서 atomic_add(), atomic_sub() 등의 함수를 볼 수 있다. static __inline__ void atomic_add(int i, atomic_t *v) { @@ -4580,7 +4580,7 @@ namespace ZNsMain while(__INTERLOCKED_COMP_EXCHANGE__==FALSE) { - // Lock ɷ ִ ̴. + // 아직 Lock 이 걸려 있는 경우이다. ::sched_yield(); }/* diff --git a/ZCppMain/ZCProcess_Win.H b/ZCppMain/ZCProcess_Win.H index baa35fc..aad9023 100644 --- a/ZCppMain/ZCProcess_Win.H +++ b/ZCppMain/ZCProcess_Win.H @@ -1,4 +1,4 @@ - + #ifndef __ZCPPMAIN__PROCESS_WIN_H__ #define __ZCPPMAIN__PROCESS_WIN_H__ @@ -18,13 +18,13 @@ namespace ZNsMain /* In WinNT : #define STATUS_WAIT_0 ((DWORD )0x00000000L) In WinBase : #define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 ) - Լ 쿡 å , ZEThread_Invalid - ̿ ȯ ִ. */ + 쓰레드 관련 함수가 에러일 경우에는 정책에 따라, ZEThread_Invalid + 이외의 값을 반환할 수도 있다. */ enum ZEThread { ZEThread_OK = 0, // =WAIT_OBJECT_0 - ZEThread_Invalid =-1, // Լ . + ZEThread_Invalid =-1, // 쓰레드 관련 함수 에러. ZEThread_TimeOut = WAIT_TIMEOUT };/* enum ZEThread*/ @@ -32,9 +32,9 @@ namespace ZNsMain /*################################################## - barrier ǥ ȯ. + ■ barrier 의 대표적인 반환값. - barrier üũ + ■ barrier 에러를 체크할 때 BarrierClass VO_BarrierClass; @@ -43,14 +43,14 @@ namespace ZNsMain // some code } - . + 로 하지 말고. if(VO_BarrierClass.Init()!=ZEBarrier_OK) { // some code } - ؾ ϴ. + 로 해야 안전하다. ##################################################*/ @@ -144,10 +144,10 @@ namespace ZNsMain /*//////////////////////////////////////////////////////////////////////////// - ZTypLong ALL_Size 0 ̸ AH_File ũⰡ ״ ȴ. - AH_File ִ ALL_Size 1 ̻ ؾ - . AH_File ȿ ̰ ALL_Size 1 ̻ ̸ AH_File - ũⰡ ALL_Size ȴ. + ZTypLong ALL_Size 가 0 이면 AH_File 에서 지정한 파일의 크기가 그대로 사용된다. + 단 AH_File 이 비어 있는 파일의 경우 ALL_Size 는 1 이상의 정수를 지정해야 한 + 다. AH_File 이 유효한 파일이고 ALL_Size 가 1 이상의 정수이면 AH_File 파일의 + 크기가 ALL_Size 로 즉시 변경된다. ////////////////////////////////////////////////////////////////////////////*/ @@ -159,11 +159,11 @@ namespace ZNsMain bool Create(HANDLE AH_File=INVALID_HANDLE_VALUE, ZTypLong ALL_Size=0, DWORD ADW_ProtectFlag=PAGE_READWRITE, ::LPSECURITY_ATTRIBUTES AP_FileMappingAttributes=NULL, LPCTSTR AP_Name=NULL)*/ - /* LPVOID AP_BaseAddress Ѵٸ system's memory allocation granularity Ѵ. - granularity ˱ ؼ GetSystemInfo Ѵ. VOID GetSystemInfo(LPSYSTEM_INFO lpSystemInfo) - . NULL ̸ ý ˾Ƽ Ѵ. */ + /* LPVOID AP_BaseAddress 를 지정한다면 system's memory allocation granularity 의 배수여야 한다. + granularity 를 알기 위해서는 GetSystemInfo 를 사용한다. VOID GetSystemInfo(LPSYSTEM_INFO lpSystemInfo) + 참고. 이 값이 NULL 이면 시스템이 알아서 정한다. */ - /* DWORD ADW_MapSize 0 ̸ ü map ȴ. */ + /* DWORD ADW_MapSize 가 0 이면 파일전체가 map 된다. */ LPVOID LinkMap(ZTypLong ALL_Offset=0, DWORD ADW_MapSize=0, DWORD ADW_DesiredAccess=FILE_MAP_ALL_ACCESS, LPVOID AP_BaseAddress=NULL) const { @@ -178,8 +178,8 @@ namespace ZNsMain }/* bool UnMap(LPCVOID AP_BaseAddress) const*/ - /* cygwin ̳ mingw ̻ϰ ::UnmapViewOfFile(void*) ǵǾ ִ. - ׷ UnMap() μ (void*)AP_BaseAddress ȯְ ִ. */ + /* cygwin 이나 mingw 에서는 이상하게 ::UnmapViewOfFile(void*) 로 정의되어 있다. + 그래서 UnMap() 에서 인수를 (void*)AP_BaseAddress 으로 형변환해주고 있다. */ bool Close() { @@ -192,7 +192,7 @@ namespace ZNsMain class ZCMemMap*/ - // ޸ Ŭ + // 공유메모리 클래스 class ZCShareMemory { @@ -227,7 +227,7 @@ namespace ZNsMain void* GetStartAddress() const*/ - // Create() ȣ LinkMap() ȣؾ Ѵ. + // Create() 멤버를 호출한 다음에는 LinkMap() 멤버를 호출해야 한다. bool Create(LPCTSTR AP_MapName, long AL_MapSize) { @@ -261,9 +261,9 @@ namespace ZNsMain and the GetLastError function returns ERROR_INVALID_HANDLE. This occurs because these objects share the same namespace. - -- lpName ̸ event, semaphore, mutex, waitable timer  - -- ϰ ִٸ GetLastError Լ ERROR_INVALID_HANDLE ȯѴ. - -- NULL ִ. + -- lpName 과 같은 이름을 event, semaphore, mutex, waitable timer 등에서 + -- 사용하고 있다면 GetLastError 함수가 ERROR_INVALID_HANDLE 을 반환한다. + -- NULL 로 지정할 수 있다. Return Value @@ -343,8 +343,8 @@ namespace ZNsMain This value is available starting with Windows XP SP2 and Windows Server 2003 SP1. Windows 2000: This value is not supported. - -- FILE_MAP_EXECUTE Ȯ ϴ 𸣰ڴ. - -- ڵμ ִٴ , ڵ  ϴ ΰ. + -- FILE_MAP_EXECUTE 이 값이 정확히 무엇을 뜻하는지 잘 모르겠다. + -- 코드로서 실행될 수 있다는 것 같은데, 그 코드의 실행은 어떻게 하는 것인가. -- 2008-02-08 21:48:00 FILE_MAP_READ @@ -415,18 +415,18 @@ namespace ZNsMain /*////////////////////////////////////////////////////////////////////////////// - class ZCProcessMutex μ ؽ. + ■ class ZCProcessMutex 는 프로세스의 뮤텍스. - Window ̸ִ mutex Linux  - ͵ ̴. pthread ̺귯 Ἥ ޸𸮿 mutex Ÿ -  ټ ϴ. Linux ߾忡 - μ  ٸ. Ȯ pthread μ mutex - ʴ´. (2006-12-28 16:02:00) + Window 에서는 이름있는 mutex 를 쓰면 간단하지만 Linux 에서는 세마포어를 쓰는 + 것도 방법이다. 물론 pthread 라이브러리를 써서 공유메모리에 mutex 데이타를 넣 + 어도 되지만 다소 복잡하다. Linux 에서는 다중쓰레드에서 쓰는 세마포어와 다중 + 프로세스에서 쓰는 세마포어가 다르다. 정확히는 pthread 가 프로세스 mutex 는 아 + 직 지원하지 않는다. (2006-12-28 16:02:00) - window ؽ '' ־ ؽ ؾ Ѵ. - ؽ ReleaseMutex(ؽ) ϸ FALSE ȯѴ. - ش ؽ ؽ ƹ ɾ ī - Ʈ ö ʴ´. īƮŭ ־ Ѵ. + window 뮤텍스에는 '소유' 라는 개념이 있어서 소유한 뮤텍스가 해제를 해야 한다. + 소유하지 않은 뮤텍스가 ReleaseMutex(뮤텍스) 를 실행하면 FALSE 를 반환한다. 또 + 한 해당 뮤텍스를 소유한 쓰레드는 그 뮤텍스에 아무리 락을 걸어도 내부 참조 카 + 운트만 올라갈 뿐 블럭되지 않는다. 또 그 카운트만큼 락을 해제해 주어야 한다. //////////////////////////////////////////////////////////////////////////////*/ @@ -452,7 +452,7 @@ namespace ZNsMain { if(lpMutexAttributes==NULL) { - // Mutex ڵ ϵ μ ְ Ѵ. + // Mutex 핸들을 차일드 프로세스로 상속할 수 있게 한다. SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES_Obj; SECURITY_ATTRIBUTES_Obj.bInheritHandle =TRUE; @@ -475,15 +475,15 @@ namespace ZNsMain /*/////////////////////////////////////////////////////////////////////////// - WaitForSingleObject() Լ ش ؽ ȣ° ƴϸ ȣ· - ְ ٷ , ȣ̸ ȣ° Ѵ. + ■ WaitForSingleObject() 함수는 해당 뮤텍스가 신호상태가 아니면 신호상태로 + 만들어주고 바로 리턴하지만, 비신호상태이면 신호상태가 될 때까지 대기한다. - 尡 ý ϸ ؽ ٸ ٸ - ° ȴ. ׷ ؽ 尡  - ؽ Ǯ ϰ Ǹ ؽ(Abandoned Mutex) Ҹ. - WaitForSingleObject() Լ ϰ WAIT_ABANDONED ޹޴ ̸ - ؽ  ó ΰ α׷ӿ ޸ ̴. - ̰ Critical Section ణ ġ ִ. + ■ 한 스레드가 뮤택스를 소유하면 이 뮤텍스를 기다리는 다른 스레드들은 + 모두 블럭 상태가 된다. 그런데 뮤텍스를 소유한 스레드가 어떠한 이유로 + 뮤텍스의 소유를 풀지 못하게 되면 포기된 뮤텍스(Abandoned Mutex) 라고 불린다. + WaitForSingleObject() 함수의 리턴값으로 WAIT_ABANDONED 값을 전달받는 경우이며 + 이 포기된 뮤텍스를 어떻게 처리할 것인가는 프로그래머에게 달린 문제이다. + 이것은 Critical Section 에 비해 약간의 안전장치가 될 수 있다. ///////////////////////////////////////////////////////////////////////////*/ }/* @@ -562,8 +562,8 @@ namespace ZNsMain /*////////////////////////////////////////////////////////// - Ʒ ٿ ZCProcessMutex() Ϳ ؼ - CProcess_Linux.H class ZZCThreadMutexEasy ּ . + ■ 아래 선언 줄에 ZCProcessMutex() 이 붙은 것에 대해서는 + CProcess_Linux.H 의 class ZZCThreadMutexEasy 의 주석을 참고. -- 2013-05-05 07:05:00 @@ -612,22 +612,22 @@ namespace ZNsMain /*///////////////////////////////////////////////////////////// - class ZCProcessSemaphore μ ȭ object. - μ ȭ Semaphore ְ Window - μ ȭ Mutex ִ. - μ ȭ ̴ Semaphore ȭ ̴ -  Լ ٸ. + ■ class ZCProcessSemaphore 는 프로세스만을 위한 동기화 object. + 리눅스에서는 프로세스 동기화에 Semaphore 만 쓸 수 있고 Window + 에서는 프로세스 동기화에 Mutex 도 쓸 수 있다. 리눅스에서는 + 프로세스 동기화에 쓰이는 Semaphore 와 스레드 동기화에 쓰이는 + 세마포어가 함수와 용법이 다르다. - class ZCThreadSemaphore ȣȯDZ - ƴ. ȣȯ ؼ class ZCProcessSemaphore - . 쿡 ̸ִ semaphore μ - ̴. + ■ 리눅스의 class ZCThreadSemaphore 는 윈도우와 상당히 호환되기 + 어렵다. 리눅스와 호환을 위해서라면 class ZCProcessSemaphore + 를 쓴다. 윈도우에서 이름있는 semaphore 는 프로세스에 전역적 + 이다. - ReleaseSemaphore() Լ ϴ ڿ 2 ̻ - ϴ ǰ ִ 尡 2 ̻  - ƴϴ. ݵ 忡 ڽ ŭ - ־ Ѵ. Posix barrier Ȯ - . + ■ ReleaseSemaphore() 함수는 해제하는 자원의 갯수를 2 이상으로 + 지정하더라도 블럭되고 있는 대기 쓰레드가 2 개 이상 깨어나는 + 것이 아니다. 반드시 현재 쓰레드에서 자신이 잠근 만큼 해제해 + 주어야 한다. 따라서 세마포어로 Posix 의 barrier 를 정확히 구 + 현할 수 없다. /////////////////////////////////////////////////////////////*/ @@ -653,7 +653,7 @@ namespace ZNsMain { /*///////////////////////////////////////////////////////////////// - cf) CreateSemaphore() + ■ cf) CreateSemaphore() Return Values If the function succeeds, @@ -679,7 +679,7 @@ namespace ZNsMain bool Make(LPCSTR AP_SemaName, LONG AL_InitialCnt, LPSECURITY_ATTRIBUTES AP_SemaphoreAttributes=NULL)*/ - // Ʒ ؽó 쿡 Ѵ. + // 아래 멤버는 뮤텍스처럼 쓰려는 경우에 사용한다. bool Make(LONG AL_InitialCnt=1, LONG AL_MaxCnt=1, LPSECURITY_ATTRIBUTES AP_SemaphoreAttributes=NULL) { @@ -689,7 +689,7 @@ namespace ZNsMain bool Make(LONG AL_InitialCnt=1, LONG AL_MaxCnt=1, LPSECURITY_ATTRIBUTES AP_SemaphoreAttributes=NULL)*/ - bool MakeZero(LPCSTR AP_SemaName=NULL) // ȣ  . + bool MakeZero(LPCSTR AP_SemaName=NULL) // 비신호상태의 세마포어를 만든다. { const int CI_MaxNumSemaphore=2100000000; @@ -710,8 +710,8 @@ namespace ZNsMain static LPCSTR GetUniqueSemaKey()*/ - /* bool MakeStd() class ZCProcessSemaphore - Window, Linux ʿ ȣȯϱ */ + /* bool MakeStd() 는 class ZCProcessSemaphore 가 + Window, Linux 양쪽에서 호환하기 위한 것 */ bool MakeStd(LPCSTR AP_SemaName, LONG AL_InitialCnt,LONG AL_MaximumCount) { @@ -726,11 +726,11 @@ namespace ZNsMain bool Open(LPCSTR AP_SemaName, DWORD dwDesireAccess=SEMAPHORE_ALL_ACCESS, BOOL bInheritHandle=TRUE)*/ - /* ´. Լ ۰ ڽ ڽ - ٰ ϰ ִ. 'API ' 1101 . + /* 현재 세마포어의 값을 가져온다. 이 함수를 만든 작가 자신은 별로 자신이 + 없다고 말하고 있다. 가남사 김상형저 'API 정복' 1101 페이지 참고. - Լ ʿϳĐ  - ʿϴ. -- 2015-09-16 00:40:00 */ + 이 함수가 언제 필요하냐먄 세마포어에서 대기 중인 쓰레드 갯수를 모니터 + 링할 때 필요하다. -- 2015-09-16 00:40:00 */ static int GetValue(HANDLE AH_Sema) { @@ -755,7 +755,7 @@ namespace ZNsMain bool IsZeroCount()*/ - // cf) WaitForSingleObject() ðʰ 쿡 WAIT_TIMEOUT Ѵ. + // cf) WaitForSingleObject() 은 시간초과의 경우에 WAIT_TIMEOUT 을 리턴한다. bool Lock(DWORD ADW_TimeOut=INFINITE) { @@ -764,8 +764,8 @@ namespace ZNsMain bool Lock(DWORD ADW_TimeOut=INFINITE)*/ - /* LockRaw() ̸ ZEThread_OK, ðʰ ZEThread_TimeOut ȯѴ. - Posix  . */ + /* LockRaw() 는 성공이면 ZEThread_OK, 시간초과는 ZEThread_TimeOut 을 반환한다. + 리눅스의 Posix 세마포어에서도 같다. */ int LockRaw(DWORD ADW_TimeOut=INFINITE) { @@ -821,12 +821,12 @@ namespace ZNsMain /*////////////////////////////////////////////// - 쿡 μ -  ʿ䰡 . + ■ 윈도우에서는 스레드용 세마포어와 프로세스용 + 세마포어를 구별할 필요가 없다. - 忡 ::EnterCriticalSection() - ߺ ȣ ʴ´. Mutex - . + ■ 같은 쓰레드에서 ::EnterCriticalSection() 의 + 중복 호출은 블럭되지 않는다. 이 점은 Mutex + 와 같다. //////////////////////////////////////////////*/ @@ -836,7 +836,7 @@ namespace ZNsMain - // posix spin lock Ѵ. + // posix 에서는 spin lock 으로 구현한다. class ZCCriticSect // Critical Section { @@ -867,7 +867,7 @@ namespace ZNsMain /*////////////////////////////////////////////////////////////////////////////////// - ̻ϰ TryEnterCriticalSection Լ ȣ . -- 2007-05-17 14:34:00) + ■ 이상하게 TryEnterCriticalSection 함수를 호출할 수 없다. -- 2007-05-17 14:34:00) bool TryLock() { @@ -917,11 +917,11 @@ namespace ZNsMain template class ZtCAutoKeyRev; - /* ZtCAutoKey<> ø Lock ϰ Ѵ. - ִ Key Ͽ. + /* ZtCAutoKey<> 템플릿은 Lock 을 설정하고 해제한다. + 열고 닫을 수 있는 열쇠와 같아 Key 라고 하였다. - ̷ RAII(Resource Acquisition Is Initialization) - Ѵٴ ˾Ҵ. -- 2015-03-10 15:08:00 + 이런 식의 기법을 RAII(Resource Acquisition Is Initialization) 라 + 고 한다는 것을 알았다. -- 2015-03-10 15:08:00 */ template class ZtCAutoKey { @@ -942,7 +942,7 @@ namespace ZNsMain ZtCAutoKey(TCriticSectEasy& AR_SyncEasy):mr_SyncEasy(AR_SyncEasy) { #ifdef _DEBUG_CAUTOKEY_ - cout<<" ZtCAutoKey:: ZtCAutoKey() "< ZtCAutoKey<> ڿ μ ޾Ƽ - ڿ Lock ϰ, Ҹڿ ٽ Lock ɾ ش. - ׷ ̷ ؾ Ȳ ü . ϴ - Dead Lock ¿ . + ■ ZtCAutoKeyRev<> 는 ZtCAutoKey<> 을 생성자에서 인수로 받아서 + 생성자에서 Lock 을 해제하고, 소멸자에서 다시 Lock 을 걸어 준다. + 그런데 이렇게 해야 될 상황 자체를 만들지 말자. 억지로 사용하다 + 보면 자주 Dead Lock 상태에 빠진다. - 2008-04-09 21:01:00 + ※ 2008-04-09 21:01:00 ////////////////////////////////////////////////////////////////*/ @@ -1007,24 +1007,24 @@ namespace ZNsMain /*//////////////////////////////////////////////////// - http://blog.naver.com/kimsk99?Redirect=Log&logNo=50004383787 + ■ 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 - ġȯ ϴ. + 윈도우 프로그램을 하면서 쓰레드를 생성할 때, CreateThread와 _beginthread라는 두 함수 중, 어떤 함수를 사용해야 할 지 고민하게 된다. + 난 항상 뭔가 기본 API같은 CreateThread를 사용해 왔었다. 그런데 오늘 책을 읽다가 그게 잘못되었다는 것을 알았다. MSDN에 나온 설명을 + 자세히 읽어보면 나오는 내용이었지만 보통 자세히는 안 읽으니 그동안 몰랐었다. 일단 CreateThread는 윈도우 SDK에서 제공하는 기본 API + 이다. 특별한 라이브러리와 링크하지 않아도 윈도우라면 컴파일되고 돌아간다. 하지만 _beginthread(또는 _beginthreadex)는 standard C + library에 속한 함수로 링크해야 동작한다. 그렇기 때문에 기능에서도 차이가 난다. 사실 기능에서 차이가 나지 않는다면 이렇게 구별할 이 + 유가 없었을 것이다. _beginthread와 같은 경우 인자의 종류가 달라서 쓰레드 생성시 필요한 설정을 할 수 없는 경우가 있다. 그러나 비슷 + 한 함수인 _beginthreadex는 완전히 CreateThread와 같은 인자를 가지고 있다. 그렇기 때문에 CreateThread 가 쓰인 모든 곳은 _beginthreadex + 로 치환이 가능하다. - εۿ ū _beginthread standard C library ϴ TLB ʱȭ شٴ ̴. standary C - library ִ Լ Ϻδ thread-safty ؼ TLB ϴµ ʱȭ ʴ´ٸ ߻ ִ. + 내부동작에서 가장 큰 차이점은 _beginthread 는 standard C library에서 사용하는 영역에 대한 TLB 초기화를 해준다는 것이다. standary C + library에 있는 함수 중 일부는 thread-safty를 위해서 TLB를 사용하는데 초기화가 되지 않는다면 문제가 발생할 수 있다. - _beginthreadex Լ ؼ 带 ߴٸ Լ 带 ϱ ؼ ExitThread Լ ϱ ٴ - _endthreadex Լ ϱ Ѵ. + _beginthreadex 함수를 사용해서 쓰레드를 구동했다면 스레드 함수 내에서 쓰레드를 종료하기 위해서 ExitThread 함수를 사용하기 보다는 + _endthreadex 함수를 사용하길 권장한다. - κ C library ϱ _beginthreadex ؾ Ѵ. + 대부분의 경우 C library를 사용하기 때문에 쓰레드의 생성은 _beginthreadex 를 사용해야 한다. uintptr_t _beginthreadex ( @@ -1036,14 +1036,14 @@ namespace ZNsMain unsigned *thrdaddr ); - -- + ■ -- ////////////////////////////////////////////////////*/ ////////////////////////////////////////////////////// - ///////////////// Ŭ ///////////////// + ///////////////// 쓰레드 관련 클래스 ///////////////// ////////////////////////////////////////////////////// @@ -1071,7 +1071,7 @@ namespace ZNsMain LPDWORD lpThreadId ); - CreateThread _beginthreadex ü ְ ׷ Ѵ. + CreateThread 는 _beginthreadex 로 대체될 수 있고 그래야 한다. dwCreationFlags [in] Flags that control the creation of the thread. @@ -1111,38 +1111,38 @@ namespace ZNsMain typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; - LPTHREAD_START_ROUTINE AP_StartAddress Լ - DWORD WINAPI ThreadFunc(LPVOID lpRarameter) + LPTHREAD_START_ROUTINE AP_StartAddress 는 시작함수포인터 + 원형은 DWORD WINAPI ThreadFunc(LPVOID lpRarameter) - ********** MFC ȭ object ********** + ********** MFC 의 동기화 object ********** - Ʒ object ؼ ʿ + 아래 object 를 쓰기 위해서는 가 필요 1) CCriticalSection cs; cs.Lock(); - // ۾ڵ + // 작업코드 cs.Unlock(); 2) CEvent event; - Thread ֵ Ǵ - CEvent object ϰ Thread CallBack Լ + Thread 들이 참조할 수 있도록 전역 또는 상위 블럭에 + CEvent object 를 선언하고 Thread CallBack 함수에서 UINT ThreadFunc(LPVOID pParam) { while(TRUE) { - CEventOvj.Lock(); // ̵. + CEventOvj.Lock(); // 잠이든다. - // ̺Ʈ ߻ ڵ带 ´. - // ׸ ܺο - // CEventOvj.PulseEvent(); ̳ - // CEventOvj.SetEvent(); ȣϸ . + // 이벤트가 발생할 때 실행될 코드를 적는다. + // 그리고 외부에서 + // CEventOvj.PulseEvent(); 이나 + // CEventOvj.SetEvent(); 를 호출하면 깨어난다. - // Thread Lock ɷ ¿ - // PulseEvent Լ ȣϸ ƹϵ Ͼ ʰ - // ٷ Lock() ȣϸ ٽ ܴ. - // SetEvent() 쿡 ׳ Ѵ. + // Thread 가 Lock 이 걸려 있지 않은 상태에서 + // PulseEvent 함수를 먼저 호출하면 아무일도 일어나지 않고 + // 바로 다음 순간에 Lock() 를 호출하면 다시 잠을 잔다. + // SetEvent() 의 경우에는 그냥 통과한다. } //while(TRUE) } @@ -1273,7 +1273,7 @@ namespace ZNsMain /*****/ )!=INVALID_HANDLE_VALUE ; ////////////////////////////////// - #if 0 // CreateThread() Լ + #if 0 // CreateThread() 함수를 쓰는 경우 DWORD VUI_ThreadID; @@ -1310,17 +1310,17 @@ namespace ZNsMain bool Make(unsigned (__stdcall AP_StartAddress*)(void *), void* AP_Arg=0, DWORD dwCreationFlags=0, DWORD dwStackSize=0, LPSECURITY_ATTRIBUTES lpThreadAttributes=NULL)*/ - // ñ Լ ()Ų. + // 쓰레드 종료시까지 메인 함수의 실행을 지연(블럭)시킨다. int Wait(DWORD ADW_MilliSeconds=INFINITE) { return ::WaitForSingleObject(mh_ThreadID, ADW_MilliSeconds); - /* WaitForSingleObject(HANDLE,DWORD ADW_MilliSeconds); 3 ȯ ´. + /* WaitForSingleObject(HANDLE,DWORD ADW_MilliSeconds); 는 3 종류의 반환값을 갖는다. - WAIT_OBJECT_0 : HANDLE object ȣ° Ǿ. - WAIT_TIMEOUT : ŸӾƿð Ͽ. - WAIT_ABANDONED : ؽ */ + WAIT_OBJECT_0 : HANDLE object 가 신호상태가 되었다. + WAIT_TIMEOUT : 타임아웃시간이 경과하였다. + WAIT_ABANDONED : 포기된 뮤텍스 */ }/* int Wait(DWORD ADW_MilliSeconds=INFINITE)*/ @@ -1328,11 +1328,11 @@ namespace ZNsMain { return ::WaitForSingleObject(AI_ThreadIDVar, ADW_MilliSeconds); - /* WaitForSingleObject(HANDLE,DWORD ADW_MilliSeconds); 3 ȯ ´. + /* WaitForSingleObject(HANDLE,DWORD ADW_MilliSeconds); 는 3 종류의 반환값을 갖는다. - WAIT_OBJECT_0 : HANDLE object ȣ° Ǿ. - WAIT_TIMEOUT : ŸӾƿð Ͽ. - WAIT_ABANDONED : ؽ */ + WAIT_OBJECT_0 : HANDLE object 가 신호상태가 되었다. + WAIT_TIMEOUT : 타임아웃시간이 경과하였다. + WAIT_ABANDONED : 포기된 뮤텍스 */ }/* static int Wait(ThreadID AI_ThreadIDVar, DWORD ADW_MilliSeconds=INFINITE)*/ @@ -1349,20 +1349,20 @@ namespace ZNsMain LPDWORD lpExitCode ); - Parameters + ■ Parameters - hThread + □ hThread [in] Handle to the thread. - lpExitCode + □ lpExitCode [out] Pointer to a 32-bit variable to receive the thread termination status. - Return Values + ■ Return Values Nonzero indicates success. Zero indicates failure. To get extended error information, call GetLastError. - Remarks + ■ Remarks If the specified thread has not terminated, the termination status returned is STILL_ACTIVE. @@ -1384,27 +1384,27 @@ namespace ZNsMain /*////////////////////////////////////////////////////////////// - SuspendThread Լ Ű - ResumeThread Լ 带 ۽Ų. + ■ SuspendThread 함수는 쓰레드의 동작을 중지시키고 + ResumeThread 함수는 중지된 쓰레드를 동작시킨다. - ī͸ ϴµ īƮ - SuspendThread Լ ȣǸ ϰ ResumeThread Լ ȣ - Ǹ ϸ īƮ 0 ̸ 簳ȴ. ׷ - SuspendThread Լ ι ȣߴٸ ResumeThread Լ ι - ȣ ־ 尡 簳ȴ. + 윈도우 쓰레드는 내부적으로 중지카운터를 유지하는데 이 카운트는 + SuspendThread 함수가 호출되면 증가하고 ResumeThread 함수가 호 + 출되면 감소하며 이 카운트가 0 이면 쓰레드는 재개된다. 그래서 + SuspendThread 함수를 두번 호출했다면 ResumeThread 함수도 두번 + 호출해 주어야 쓰레드가 재개된다. - ׷ٸ ResumeThread ȣϰ SuspendThread ߿ - ȣϸ  ɱ. 쿡 ȴ. īƮ -1 - 0 Ǿ īƮ - 0 ̸δ ʴ . + 그렇다면 ResumeThread 를 먼저 호출하고 SuspendThread 를 나중에 + 호출하면 어떻게 될까. 이 경우에는 블럭된다. 내부 카운트가 -1 + 에서 0 으로 되어 계속 진행할 것으로 예상하지만 내부 카운트는 + 0 미만으로는 셋팅이 되지 않는 것 같다. - POSIX ǥؾȿ ̷ Լ µ, POSIX 带 - α׷ (ȭ, David R. Butenhof) 301 Page - suspend resume ִ. + POSIX 쓰레드표준안에서는 이런 함수가 없는데, POSIX 쓰레드를 이 + 용한 프로그래밍 (정보문화사, David R. Butenhof) 301 Page 에 + suspend 와 resume 를 구현한 예제가 나와있다. - ֶ󸮽 thr_suspend(), thr_continue() Լ Ѵ. + 솔라리스에서는 thr_suspend(), thr_continue() 함수를 지원한다. - -- + ■ -- //////////////////////////////////////////////////////////////*/ @@ -1493,7 +1493,7 @@ namespace ZNsMain /*****/ )!=INVALID_HANDLE_VALUE ; /////////////// - #if 0 // CreateThread() Լ + #if 0 // CreateThread() 함수를 쓰는 경우 DWORD VUI_ThreadID; @@ -1586,31 +1586,31 @@ namespace ZNsMain /*/////////////////////////////////////////////////////////////////////////////// - ȣ : 㰡ϴ + ■ 신호상태 : 쓰레드의 실행을 허가하는 상태 - ڵ ̺Ʈ : ° Ǹ ڵ ȣ ° ȴ. - ̺Ʈ : 尡 ȣ · ȣ¸ Ѵ. + 자동 리셋 이벤트 : 대기 상태가 종료되면 자동으로 비신호 상태가 된다. + 수동 리셋 이벤트 : 쓰레드가 비신호 상태로 만들어 줄 때까지 신호상태를 유지한다. - SetEvent ̺Ʈ ȣ· , - ResetEvent ̺Ʈ ȣ· . - ( ٸ 尡 · .) + SetEvent 는 이벤트를 신호상태로 만들고, + ResetEvent 는 이벤트를 비신호상태로 만든다. + (즉 다른 쓰레드가 진입할 수 없는 상태로 만든다.) - ڵ ̺Ʈ 尡 WaitForSingleObject() ȣϸ ٸ - SetEvent() Լ ̺Ʈ ȣ · Ȥ ðŭ - ȴ. + 자동 리셋 이벤트를 만든 쓰레드가 WaitForSingleObject() 를 호출하면 다른 쓰레드 + 가 SetEvent() 함수로 그 이벤트를 신호 상태로 만들 때까지 혹은 지정한 시간만큼 + 블럭된다. - ̺Ʈ ټ 尡  ٸٰ Ǿ - ϰ ϴ ִµ ǵ/ lock ̳ ؽ - ִ. ε ִ. ټ 尡 -  ϰ ִٰ  Ǹ īƮ - ŭ ÷ָ 尡  ̴. + 이벤트는 다수의 쓰레드가 어떤 조건을 기다리다가 그 조건이 충족되었을 때 일제히 + 시작하게 하는 기능을 할 수 있는데 리눅스에서는 판독자/기록자 lock 이나 뮤텍스의 + 조건 변수로 구현할 수 있다. 물론 세마포어로도 할 수 있다. 다수의 쓰레드가 세마 + 포어에서 대기하고 있다가 어떤 해제 조건이 되면 세마포어 카운트를 쓰레드 갯수만 + 큼 늘려주면 모든 쓰레드가 깨어날 것이다. -  ϴ , ( ׽Ʈغ ʾ) Window - īƮ ϴ ŭ ÷־ 尡 - ѹ  ʾҴ. īƮ 1 Ű ڵ带 - ŭ ־ Ѵ. + 세마포어를 사용하는 경우, (리눅스에서는 테스트해보지 않았지만) Window 에서는 단 + 순히 세마포어 카운트를 대기하는 쓰레드 갯수만큼 늘려주어도 모든 대기 쓰레드가 + 한번에 깨어나지 않았다. 세마포어 카운트를 1 증가시키는 코드를 대기 쓰레드 갯수 + 만큼 실행해 주어야 한다. - 2008-05-05 15:38:00 + ※ 2008-05-05 15:38:00 ///////////////////////////////////////////////////////////////////////////////*/ @@ -1623,7 +1623,7 @@ namespace ZNsMain /*////////////////////////////////////////////////////////////////////////////// - CreateEvent() + ■ CreateEvent() A handle to the event object indicates success. If the named event object existed before the function call, @@ -1639,13 +1639,13 @@ namespace ZNsMain }/* bool Make(LPCTSTR AP_Name, BOOL AB_Reset=TRUE, BOOL AB_ManualReset=TRUE, LPSECURITY_ATTRIBUTES AP_SecAtt=NULL)*/ - bool Set() const // ̺Ʈ ȣ· . + bool Set() const // 이벤트를 신호상태로 만든다. { return ::SetEvent(mh_TypeID)==TRUE; }/* bool Set() const*/ - bool Reset() const // ̺Ʈ ȣ· . + bool Reset() const // 이벤트를 비신호상태로 만든다. { return ::ResetEvent(mh_TypeID)==TRUE; }/* @@ -1657,10 +1657,10 @@ namespace ZNsMain /*////////////////////////////////////////////////////////////////////////////////////////////////////// - ̺Ʈ SetEvent() Լ ȣϿ ̺Ʈ ȣ · . ׸ ϴ 尡 - ¸  ٽ ڵ ̺Ʈ ȣ · ش. ׷ϱ ̺Ʈ - ڵ ̺Ʈ ȿ ִ Լ̴. ׷ MSDN Ҿϱ - ִ. + ■ 수동리셋 이벤트에서 SetEvent() 함수를 호출하여 이벤트를 신호 상태로 만든다. 그리고 대기하던 쓰레드가 + 대기 상태를 벗어나면 다시 자동으로 이벤트를 비신호 상태로 만들어준다. 그러니까 수동 리셋 이벤트에서 + 자동 리셋 이벤트 효과를 가져다 주는 함수이다. 그런데 MSDN 에서는 불안정하기 때문에 사용하지 말라고 되 + 어 있다. http://msdn.microsoft.com/en-us/library/ms684914(VS.85).aspx @@ -1670,14 +1670,14 @@ namespace ZNsMain Note : This function is unreliable and should not be used. It exists mainly for backward compatibility. For more information, see Remarks. - ϱ⸦ + ■ 위에서 정리하기를 - " ̺Ʈ ڵ ̺Ʈ ȿ ִ Լ̴." + "수동 리셋 이벤트에서 자동 리셋 이벤트 효과를 가져다 주는 함수이다." - ߴµ ̰ Ʋ. ̺Ʈ ȣ · , ̺Ʈ ϴ 尡  - Ȯ Ŀ ̺Ʈ ٽ ȣ · . ̺Ʈ ȣ · , - Ʈ ϴ 尡  Ⱓ ؾ Ѵ. Ƹ κ ó Ҿ - ϱ MSDN "unreliable" ̶ ̴. + 라고 했는데 이것은 틀리다. 이벤트를 신호 상태로 만들고, 그 이벤트에서 대기하던 모든 쓰레드가 깨어난 + 것을 확인한 후에 그 이벤트를 다시 비신호 상태로 만든다. 따라서 이벤트를 신호 상태로 만든 다음, 그 이 + 벤트에서 대기하던 모든 쓰레드가 깨어날 때까지 일정 기간을 대기해야 한다. 아마 이 부분 처리가 불안정 + 하기 때문에 MSDN 에서 "unreliable" 이라고 했을 것이다. -- 2009-02-05 0:10:00 @@ -1694,13 +1694,13 @@ namespace ZNsMain /*////////////////////////////////////////////////////////////////////////////////////// - ::WaitForSingleObject() ȯ + ■ ::WaitForSingleObject() 의 반환값 WAIT_OBJECT_0 : The state of the specified object is signaled. WAIT_TIMEOUT : The time-out interval elapsed, and the object's state is nonsignaled. WAIT_FAILED : Fail - Ʒ Lock 迭 Լ ƴϸ ZEThread_OK ZEThread_TimeOut ȯ ִ. + 아래 Lock 계열 함수는 에러가 아니면 ZEThread_OK 나 ZEThread_TimeOut 을 반환할 수 있다. //////////////////////////////////////////////////////////////////////////////////////*/ @@ -1722,7 +1722,7 @@ namespace ZNsMain }/* int LockTime(DWORD AI_TimeOutMili)*/ - bool UnLock() const // ̺Ʈ ȣ· . + bool UnLock() const // 이벤트를 신호상태로 만든다. { return this->Set(); }/* @@ -1752,14 +1752,14 @@ namespace ZNsMain /*///////////////////////////////////////////////////////////////////////////// - Init() Fini() ȯ linux ȣȯ bool ƴϰ int ̴. - ȯ ٷ + ■ Init() 와 Fini() 의 반환값이 linux 와 호환을 위해 bool 이 아니고 int 형이다. + 반환값을 다룰 때는 if(CBarrierObj.Init(3)==ZNsEnum::ZEBarrier_OK) - ̷ . + 이런 식으로 하자. - Init() Լ ȣ ̺Ʈ . + ■ Init() 함수는 비신호 상태인 수동 리셋 이벤트를 만든다. /////////////////////////////////////////////////////////////////////////////*/ @@ -1769,7 +1769,7 @@ namespace ZNsMain /*//////////////////////////////////////////////////// - ::CreateEvent() 3 μ : bInitialState + ■ ::CreateEvent() 의 3 번 인수 : bInitialState If this parameter is TRUE, the initial state of the event object is signaled; @@ -1813,7 +1813,7 @@ namespace ZNsMain /*//////////////////////////////////////////////////////////////////////////////// - LONG __cdecl InterlockedDecrement(__inout LONG volatile *Addend); + ■ LONG __cdecl InterlockedDecrement(__inout LONG volatile *Addend); Parameters : Addend [in, out] : A pointer to the variable to be decremented. Return Value : The function returns the resulting decremented value. @@ -1832,7 +1832,7 @@ namespace ZNsMain This function generates a full memory barrier (or fence) to ensure that memory operations are completed in order. - Provides compiler intrinsic support for the Win32 Platform SDK InterlockedDecrement function. + ■ Provides compiler intrinsic support for the Win32 Platform SDK InterlockedDecrement function. long _InterlockedDecrement( long * lpAddend @@ -1880,13 +1880,13 @@ namespace ZNsMain If the result of the operation is greater than zero, the return value is positive, but it is not necessarily equal to the result. - MSDN Ǵϸ InterlockedDecrement Լ - _InterlockedDecrement~ 迭 SDK ϴµ ̵ SDK - ' ҵ ȯ ʴ´' ִ. ̰ Լ + ■ 위의 MSDN 정보로 판단하면 InterlockedDecrement 함수는 + _InterlockedDecrement~ 계열의 SDK 를 사용하는데 이들 SDK 는 + '꼭 감소된 값을 반환하지는 않는다'는 것을 알 수 있다. 이것은 함수 LONG __cdecl InterlockedIncrement(__inout LONG volatile *Addend); - ؼ ̴. + 에 대해서도 마찬가지이다. ////////////////////////////////////////////////////////////////////////////////*/ @@ -1899,15 +1899,15 @@ namespace ZNsMain /*/////////////////////////////////////////////////////////////////// - ̿ؼ Ȱ ִ barrier Ŭ ø + ■ 조건 변수 개념을 이용해서 재활용할 수 있는 barrier 클래스 템플릿 - ZtCBarrier<> ټ ̴. + ■ ZtCBarrier<> 보다 다소 무겁다. - event 2 Ѵ. ϳ Դ̰ ϳ - 尡 Ǯ⸦ Ȯϴµ Ѵ. + ■ event 2 개를 사용한다. 하나는 쓰레드 진입대기용이고 또 하나는 진입 + 대기한 쓰레드가 모드 풀려나기를 확인하는데 사용한다. - ׽Ʈ ̻ϰ lock ɸ ִ. ȭ ɶ - . + ■ 테스트 결과 이상하게 어느 시점에 lock 이 걸리고 있다. 안정화 될때 + 까지 사용하지 말자. -- 2009-01-22 23:06:00 @@ -1936,7 +1936,7 @@ namespace ZNsMain protected: TSyncExec mo_CSyncExec; ZTypeID mh_EventID ; - ZTypeID mh_EWaitID ; // ϴ ̺Ʈ + ZTypeID mh_EWaitID ; // 대기 목적으로 사용하는 이벤트 int mi_BarrCnt ; int mi_WaitCnt ; EStep me_EStep ; @@ -2029,7 +2029,7 @@ namespace ZNsMain if(--mi_BarrCnt>0) { #ifdef _DEBUG - cout<<" Wait Barrier : mi_BarrCnt="< Project -> Settings -> c/c++ -> Category -> Code Generation -> Use run-time library -> - Ƽ ̺귯 Ͽ - Ǵ, ɼǿ /MT, /MD, /MTd, /MDd ߿ ϳ Ѵ. - /MT ũ - /MD ũ - /MTd ũ(DEBUG ) - /MDd ũ(DEBUG ) - -- + 멀티쓰레드 라이브러리 중 선택하여 설정 + 또는, 컴파일 옵션에 /MT, /MD, /MTd, /MDd 중에 하나를 설정한다. + /MT …… 정적링크 + /MD …… 동적링크 + /MTd …… 정적링크(DEBUG 판) + /MDd …… 동적링크(DEBUG 판) +■ -- ////////////////////////////////////////////////////////////////////////////*/