Thread design에 대한 이해는, 기본적으로 잠금 정책에 over head를 이해하고 있느냐에서 출발한다고 생각합니다.


잠금 기반 프로그래밍은, 자주 사용하는 코드가 잠기게 될수록 성능이 수직 하향합니다.

대기 하느라, 제대로 된 퍼포먼스를 낼 수 없다는 얘기죠.


그렇게 하지 않기 위해, 객체 간에 잠금에 신경쓰지 않게끔, 객체 간 접점을 줄여주어야 합니다.

 

좋은 Thread design의 목표는 어떻게 잡아야 할까요?

 

접점 최소화

손쉬운 비동기 처리

의도한 대로 순차 처리 (순서가 중요한 동작의 순서 보장)

 

디테일하게 나열하자면 얼마든지 많겠지만, 저는 위 세가지 목표가 보장된 기반 코드는, 컨텐츠 구현 시에 필요한 요구 사항을 다수 충족 시킬 수 있습니다.



이런 문제가 현세대 멀티스레드 프로그래밍의 최선이라고 여겨졌는지, 많은 솔루션이 이런 니즈를 충족시키는 데에 최적화되서 개발이 되었습니다.


node.js는 무거운 작업마다 비동기로 던지고, 그 결과 값을 바탕으로 진행할 다음 작업을 지정함으로써 잠금과 순서를 고민하지 않는 프로그래밍을 유도하고 있습니다.

만약 무거운 작업을 비동기로 처리하지 않는다면, 프로그래머의 실수라고 규정 짓는 가이드라인을 제시했습니다.



erlang도 마찬가지입니다.

기본적으로 메시지로만 통신을 유도하면서, 각 작업 간에 겹치는 상황을 제거함으로써, 잠금을 고민하지 않도록 했죠.



이렇게 할때의 언어에 구애 받지 않는 핵심은, 작업마다 독립적으로 동작할 수 있어야 한다는 점입니다.




로직을 작성하는 데에 있어서, 이 객체마다 잠금을 걸었다 풀어주는 과정은 잠재적 성능 저하 지점을 만드는 과정이라 볼 수 있습니다.


아무리 측정을 자주 하는 팀이라 할지라도, 기존에 (논리적으로도, 성능 적으로도) 잘 동작하던 코드가 병목이 될 수 있는지 여부는 의심을 덜하기 마련이기 때문이죠.


그런 잠재적 우려 지점을 변수가 추가될 때 마다 늘리는 방식은 결코 좋다고 보기 어렵다는 결론에 도달해, 현재의 모델이 최선이라고 느끼는 상황이죠.



애초에 작업들이 모두 작게 쪼개져 있고, 그간에 영향을 받지 않는다고 확신 할 수 있다면 당연하게도 대기 없는 비동기 처리가 가능해집니다.


로직을 작성하는 사람이 고민해야 될 대상중에 순서만이 남은 것이죠.


작업들을 비동기로 분리하고 난 뒤의 로직의 순서 조절은 상대적으로 쉬운 문제가 됩니다. 결합도를 고민하지 않아도 되는 상황이 되어버렸기 때문에, 순서 보장 기능을 라이브러리나 프레임워크 단에서 지원 (혹은 스크립팅으로 조절) 해주기 쉽고, 그렇지 않은 경우에 구현하는 문제도 순서 보장 작업끼리 같은 큐를 사용하게만 해줘도 되는 것이죠.



요약하자면 비동기 프로그래밍에서의 성능을 장점으로 삼는 다수의 언어와 프레임워크가 내린 합리적인 선의 비동기 프로그래밍은, 작업간 결합도를 줄인 후, 작업을 병렬로 수행해 성능 향상을 노리는 쪽으로 가고 있습니다.


제 생각도, 합리적인 선의 선택이라고 보여집니다. 극한의 성능도 중요하지만, 로직 작성의 난이도를 낮추는 것도 중요한 문제거든요. 실수할 여지를 줄이는 장점도 물론 옵션이겠고요.



지금까지 thread-design에서의 잠금 최소화 프로그래밍에 대해 알아보았습니다.


Posted by 엘키 엘키

댓글을 달아 주세요

https://nssm.cc/


 nssm-2.24.zip


rails 서비스화에 사용한 배치 파일 예제입니다. 아주 간단해요.

윈도우 서버의 경우 권한 문제에 빠질 수 있는데, 이 경우 아래 링크처럼 대처하세요.

http://elky.tistory.com/561


Install_web.bat

pushd %~dp0

@echo off


%cd%\nssm.exe install %1 C:\RailsInstaller\Ruby2.1.0\bin\rails.bat "s -p 8000 -e production"

%cd%\nssm.exe set %1 AppDirectory %cd%



Start_web.bat

pushd %~dp0

@echo off


net start %1



Stop_web.bat

pushd %~dp0

@echo off


net stop %1



Uninstall_web.bat

pushd %~dp0

@echo off


net stop %1


nssm.exe remove %1 confirm

Posted by 엘키 엘키

댓글을 달아 주세요


service_wrapper.zip


콘솔 프로그램을 service로 등록해주는 instsrv, srvany의 wrapping batch 파일입니다.


사용법은 

install.bat "서비스명" "실행파일경로" "인자"


uninstall.bat "서비스명"


입니다.

Posted by 엘키 엘키

댓글을 달아 주세요

제가 프로그래밍을 처음 배울 때의 CLI 프로그래밍과 WIN32 프로그래밍으로 넘어왔을 괴리를 느꼈습니다.

이유는 바로 EVENT-DRIVEN(message based)프로그래밍 때문이었죠.

현재는 reactor라는 패턴이란 이름으로 알려진 메시지 기반 프로그래밍은, DOS 시절의 동기 프로그래밍에 익숙한 많은 프로그래머를 괴롭게 했습니다.

 

message라는걸 굳이 만들어 처리하는가…. 대해 저는 당시 이해하기 어려웠습니다.

당시만해도, 윈도우 메시지를 굳이 처리하지 않고도 여러 작업이 가능했기 때문이죠.

 

예를 들어 GetAsyncKeyState (http://msdn.microsoft.com/ko-kr/library/windows/desktop/ms646293(v=vs.85).aspx) 같은 함수로도 얼마든지 입력 처리가 가능했고, 마우스 입력도 마찬가지였죠.

 

굳이 메시지 핸들러 코딩을 해줘야 하는지 이해가 갔어요. 특히나 윈도우 기본 컨트롤들을 사용하지 않았기 때문이기도 겁니다.

 

때가 98 경이었는데, COM 기반의 메소드를 통해 초기화하던 Direct-X가 이해 안던… ( 당시엔 COM 뭔지도, 저렇게 복잡하게 포인터 캐스팅하는지도 이해가 어려웠습니다) 시기였습니다.

 

코어도 개이던 시절이라, multithread  프로그래밍은 n개의 CPU 꽂아 쓰는 서버나 슈퍼 컴퓨터 사용자들에게나 필요한 걸로 치부 되기도 했습니다.

 

헌데…그 어렵디 어렵다던 multithread 프로그래밍이 사실은 WIN32 프로그래밍에선 각종 API 통해 이루어지고 있었고, 메시지 핸들링 코드는 다른 thread (다른 프로세스에서 오는 메시지도 있지만)에서의 처리 결과를 전달하는 코드이기도 했다는 한참이 지나서야 알게 됐습니다.

 

깊게 알아내지 못한 잘못도 있지만, 책과 PC통신을 제외하곤 정보를 얻기 힘든 당시 상황을 감안하면, 친절하게 설명해주지 못한 당시 WIN32 프로그래밍 입문서들의 문제도 있습니다.

 

! 여기서 핵심은, WIN32 어플리케이션을 만들어온 과정이 사실은 multithread 프로그래밍을 해왔다라는 점이에요. 우리가 몰랐을 뿐이죠.

 

모를 있었다는 것은, 사실 WIN32 메시지 핸들러를 통한 thread  모델이 안정적이고, 디자인된 thread design 하나라고 있습니다. WIN32 메시지 핸들링 방식은 메시지 루프를 통해 비동기 작업들을 처리해야 때에만 양보하고 다시 thread 루프로 돌아오게 해주었던 안정적인 thread design API 구성했죠.

 

이로써, multithread 대한 이해 없이, 그리고 thread 동기화에 신경 쓰지 않고도 비동기 프로그래밍을 있었습니다.

 

그렇습니다! 우리는 WIN32 메시지 기반 프로그래밍을 통해 Reactor thread design 경험한 것입니다!

 

정리하자면, thread design이란 다음 요구사항을 충족해야 한다고 보시면 됩니다.

  1. 객체를 lock 신경 써야 부분, 그렇지 않은 부분을 명확히 규정
    -> 프레임워크단에서만 신경쓰도록 구현하는 것을 권장하지만, 개체 단위 lock이 정책인 경우도 있습니다.
    -> 개체 단위 lock으로 구현한 경우에는, 코딩 난이도 상승, 병목 지점 감지도 어려워질 뿐더러, 데드락 위험성도 높아져 좋지 않은 디자인이라고 봅니다.

  2. API 사용법만 준수하면 최대한 많은 코딩 영역에 thread 동기화를 고민하지 않도록 하는
    -> 이 부분이 사실 핵심인데, thread design이 잘 되어 있을 수록, 성능도 만족하면서 유지 보수 난이도가 급격하게 낮아진다고 보시면 됩니다.

  3. Blocking 동작이나, 반복작업, 병렬 수행이 필요한 작업등을 지원하기 위해 비동기 작업을 위임하거나, 분산할 있는 기능
    -> thread pool을 통한 작업 분배, open MP등으로 지원된 병렬 코드 수행등을 떠올리시면 좋습니다.

 

WIN32 메시지 기반 모델에서는 병렬 작업을 위한 분산 기능은 미흡했으나, (시기적인 부분을 감안해 줘야 된다고 생각합니다만) 이외의 요구 사항은 충족합니다.


이렇듯 thread design이란 곳에 있지 않았습니다!

Posted by 엘키 엘키

댓글을 달아 주세요

클럭도 물론 중요하지만, 코어가 몇갠지 부터 보는 일이 자연스러워진지도 몇년.

다들 병렬 프로그래밍 잘 하고 계시나요?

서버 프로그래밍을 시작한 2006년부터 지금까지... 멀티 스레드를 다뤄오며, 느낀 것에 대해 이야기해보고자 한다.

lock
말그대로 잠금. 이 데이터 unlock 될때 까지 쓰지말라는 거다.

- non-blocking
non-blocking이 뭐냐고? 대기하는 상황(blocking) 없이 코드가 수행되는 것을 말한다.

- lock is blocking.
lock이라는 것 자체가 blocking을 위한 녀석이다. 멀티스레드에 적합한 녀석 일리 없다.

- lock-free
container나 데이터에 접근할 때에 lock 객체에 대한 고민없이 사용해도 되는 자료구조나 스레드 모델을 lock-free라고 통칭한다.
좀 더 디테일하게 설명하자면 lock-free container, lock-free design이라 칭해도 되겠다.


atomic operation
- atomic operation (or atomic instruction)
CAS (http://en.wikipedia.org/wiki/Compare-and-swap) 기반의 명령어 집합을 의미한다.
windows 에선 Interlocked 계열 메소드(http://msdn.microsoft.com/en-us/library/windows/desktop/ms684122(v=vs.85).aspx)를 통해서 지원한다. software적으로 직접 구현도 가능하다. (Interlocked 계열 메소드도 software적 구현)

- limit of atomic operation
atomic operation이 해결해 주는 것도 꽤나 많다. 객체단위 lock보다, CAS는 잠금 시간이 짧다.
다만 그로 인해 성능은 좋아질 지언정 논리상 오류가 없을까? 기본적인 전치검사 후치보장 룰을 깨뜨릴 가능성이 높다.
결국엔 논리적 오류까지 해소하기 위해선 스레드 디자인이 필요하다는 얘기다.

parelell
- lock and paralell
애초에 lock이란 pararell과 어울리지 않는 단어.
허나 locking을 minimal 하는 목표를 갖고 pararell 하게 구현해보자.

- reactor, proactor
reactor : dispatching based.

proactor : callback based.

조금 더 자세히 보자면 proactor는 이 작업을 비동기로 수행하고 그 결과를 알려주세요라는 개념이고, reactor는 어떠한 작업이 언제 완료될지 모르니, 작업에 대한 통지가 오길 기다리는 개념이라고 보면 된다.

thread-design
- entry point
진입점이 명확하면 좋다. 데이터를 발생 시키는 지점부터 고민해야 한다.
내 경험상 수 많은 서버가, entry point의 종류로 network receive, cyclic action (internal looping), system thread (api internal thread) callback, packet process thread 정도가 주를 이룬다.
이 위치를 명확히 파악해두어야, 부하에 대한 tracking이 쉬워진다.

- contact point
각 entry point에서 발생된 event들이 겹치는 지점을 말한다. entry point가 종류별로 여러 스레드로 구성 되어 있을 경우 특히나 contact point가 겹치곤 하는데, 이 위치에 lock을 놓는 전략이 가장 쉽지만, 성능 저하를 일으키는 지점이 되곤한다.

- thread count
스레드 갯수는 경합 확률을 높인다. 하지만, 잘 되어있는 스레드 디자인이 이를 우회할 수 있다.
blocking 되는 상황이 있는 thread와, 할 일이 있다면 쉬지 않고 일하는 non-blocking thread를 파악하고, 그 갯수를 비례해서 조절하는 것이 좋다.

sleep 함수도 마찬가지다. 현재 context를 이관하는 선택은, blocking이 되는 상황이 되고 있다는 것을 전제한다.

- tip
contact point는 필연적으로 lock을 강제당한다.  
contact point를 제거할 수 없다면, contact point를 갈라주거나, locking을 minimize 하는 노력을 기울여야 한다.

- lock minimize
-> contact point가 줄어들면 자연스레 lock을 최소화 해서 사용할 수 있게 된다.

-> contact point를 줄이는 쉬운 팁은 thread마다 다른 instance에 접근하도록 하는 것이다. 
-> 예를 들어 MMORPG에서 지역별로 다른 message worker를 이용하도록 하면, 잠금없이 스레드가 동작할 수 있다.
-> 다른 지역간의 interaction이 일어나는 동작을 개체단위 lock이 아닌 message로 수신해서 처리하는 방식으로 한다면, message queue에 밀어넣는 잠깐의 지연만 걸릴 뿐이다.

-> 조금 더 쉽게 정리하자면, 개체의 소유권을 각 스레드에 두고, 입력과 출력은 message로써 다루면 lock을 줄일 수 있다.



warning
- event explosion
어떻게 구현하건간에 처리량은 한계가 있다.
이벤트량 자체가 폭발하지 않게끔제어해야 한다.

예를들면 패킷을 수신하는데, 비정상 적인 수의 패킷을 발생 시킨다면, flooding 처리를 해야 한다.
또한 로직에서 아이템 처리를 위해 여러개 티어를 거친다고 생각해보자. 아이템 획득 처리, 아이템 로그, 퀘스트 달성 여부, 이벤트 진행인지 검사 이벤트 등... 모든 컨텐츠의 티어가 잘게 나누어져 있고, 처리 티어들을 한번씩만 거친다고 해도 이벤트량 자체는 많을 수 밖에 없다.

티어를 너무 잘게 쪼갠다면, 데이터를 완성 시키기 위한 과정에서의 이벤트량 자체가 많아지고, 오류 발생의 여지도 늘어난다.


- hot spot
latency는 두 종류가 있다.
1. 절대적인 처리량이 많아서. (event explosion으로 인한 처리량이 많아진 상황도 포함한다)
2. 병목 지점에서 대기가 이루어져, 전체 대기 시간이 길어지는 상황.

이 중 2번의 주 원인은 hot spot에 있다. 
hot spot이 발생했다는 것 자체가, contact point에서의 지연이 발생하거나, contact point에 동시 접근하는 스레드가 많다는 의미다.
다시 한번 강조하자면, thread design이 그래서 중요하다.

maintain
- profiling
측정하라. entry point부터 processing이 끝난 시점까지 측정하는 것은 너무나도 당연하지만 생각보다 이에 대한 모니터링이 이루어지지 않는 경우도 많다.
이벤트 갯수, 이벤트 처리시간, 오류 발생, 경고 등 지표화 할 수 있는 데이터들을 잘 남겨 두는 것이 중요하다.

프로파일링은 기능의 일부처럼 다뤄져야한다. 

번거롭고, 거추장스러워 문제가 생기고 나서야 확인하는 범행 현장 조사 같은 일이 되어서는 안된다.

- base line
처리 속도와 처리 시간의 목표 지점을 설정하라. 한 패킷이 5ms이하로 동작하리라 목표로 삼는다면, 1스레드당 200개 패킷을 처리할 수 있다는 전제를 세울 수 있다.
처리량을 기준으로, 한 서버당 가용 동접이 설정 가능해진다.

정상, 경고, 임계, 장애등의 수위를 정해놓고 각 수위별로 다른 알람을 받으면 좋다.
또한 runtime에 해당 수치를 낮출 수 있는 대안 (컨텐츠별 block)을 마련해두어 대응할 수 있어야 한다.



스레드 디자인에 대한 내용은 다음 글에서 따로 다뤄보고자 합니다. 꽤나 길어질거 같군요.

제 생각에 대한 이의나 다른 의견, 질문 뭐든지 환영합니다.

이상으로 멀티 스레드 프로그래밍의 퍼포먼스 해결을 위한 팁을 정리해보았습니다.


Posted by 엘키 엘키

댓글을 달아 주세요

1.Critical Section

 - 유저 레벨의 동기화 방법 중, 유일하게 커널 객체를 사용하지 않음.

 - 내부 구조가 단순하여 동기화 처리에 대한 속도가 빠르다.

 - 동일한 프로세스 내에서만 사용.

 - 커널 객체를 사용하지 않기 때문에 핸들을 사용하지 않고, CRITICAL_SECTION 이라는 타입을 정의하여 사용.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 크리티컬 섹션을 초기화한다.
// 파라메터는 여러 개의 쓰레드에 참조되어야 하므로 전역으로 선언하도록 한다.
void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
 
// 생성된 크리티컬 섹션을 삭제한다.
void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
 
// 동기화 방법
void workFunc()
{
    EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); // 호출. lock.
 
    // 여기서 공유 자원을 안전하게 액세스한다.
 
    LeavCriticalSection(LPCRITICAL_SECTION lpCriticalSection); // 호출. unlock.
}

2. 동기화 대기 함수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMiliseconds);
// hHandle : 동기화 객체.  dwMiliseconds : 대기 시간
// 대기 시간을 INFINITE로 지정하면 무한대로 대기한다.
// 반환 값의 종류는 세가지다.
//  WAIT_OBJECT_0 : 성공
//  WAIT_TIMER : 동기화 객체가 시그널 상태
//  WAIT_ABANDONED : 대기시간 초과
 
DWORD WaitForMulipleObject(DWORD nCound, CONST HANDLE *lpHandles,
                            BOOL fWaitAll, DWORD dwMiliseconds);
// WaitforSingleObject 함수는 하나의 객체에 대한 동기화를 기다리는데 비해 이 함수는
// 복수 개의 동기화 객체를 대기할 수 있다. 동기화 객체의 핸들 배열을 만든 후 lpHandles 인수로
// 배열의 포인터를 전달해 주고 nCount로 배열의 개수를 넘겨준다.
// fWaitAll이 TRUE이면 모든 동기화 객체가 시그널 상태가 될 때까지 대기하며,
// FALSE이면 그 중 하나라도 시그널 상태가 되면 대기 상태를 종료한다.
// 리턴 값의 의미는 조금 다르다.
//  WAIT_TIMEOUT : 대기시간 초과
//  WAIT_OBJECT_0 : bWaitAll이 TRUE일 때 - 모든 동기화 객체가 시그널 상태.
//      FALSE일 때 - lpHandles 배열에서 시그널 상태가 된 동기화 객체의 인덱스를 반환.
//      이 경우 lpHandles[리턴값 - WAIT_OBJECT_0]의 방법으로 시그널 상태가 된
//      동기화 객체의 핸들을 얻을 수 있다.

 

3. Mutex (MUTual EXclusion)

 - 최초 Signaled 상태로 생성되며, WaitforSingleObject()와 같은 대기 함수를 호출함으로써 NonSignaled 상태가 된다.

 - 크리티컬 섹션에 비해서 느리다. 크리티컬 섹션의 경우 구조체의 값을 통해 잠그기를 허용하는데 비해 뮤텍스는 객체를 생성하기 때문이다.

 - 만약 A라는 쓰레드가 뮤텍스를 소유하고 있고, B라는 쓰레드가 뮤텍스를 사용하기 위하여 대기하고 있을 때, A 쓰레드가 잘못된 연산을 수행하거나 강제 종료되어서 소유하고 있던 뮤텍스를 반환하지 않았을 때에 B라는 쓰레드는 뮤텍스를 얻기 위해 무한정 기다려야 할까?  => 만약 크리티컬 섹션을 사용하였다면 B 쓰레드는 무한정 대기하기 된다.(데드락) 하지만, 뮤텍스의 경우는 자신이 소유한 쓰레드가 누군지 기억하고 있다. 그리고 Windows 운영체제에서 뮤텍스를 반환하지 않는 상태에서 쓰레드가 종료될 경우 그 뮤텍스는 강제적으로 Signaled 상태로 만든다.

 - 만약 같은 쓰레드가 중복으로 뮤텍스를 호출할 경우 데드락이 발생할까? => 발생하지 않는다. 왜냐면 같은 쓰레드가 중복으로 뮤텍스를 호출할 경우는 내부 Count만 증가시키고, 진입은 허용한다. 그리고 나중에 내부 Count가 '0'으로 될 때 Singaled 상태로 해준다. (이 부분은 크리티컬 섹션도 동일한 개념이다.)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName);
// lpMutexAttributes는 보안 속성으로 보통 NULL로 지정한다.
// bInitialOwner는 뮤텍스 생성과 동시에 소유할 것인지 지정하는데 TRUE이면 이 쓰레드가 바로 뮤텍스를
// 소유하면서 다른 쓰레드는 소유할 수 없게 된다.
// lpName은 뮤텍스의 이름이다. NULL 설정 가능.
// 리턴 값은 뮤텍스의 핸들이다.
 
HANDLE OpenMutex(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName);
// 뮤텍스를 연다. 프로세스 ID와 마찬가지로 뮤텍스의 이름은 전역적으로 유일하다.
 
BOOL ReleaseMutex(HANDLE hMutex);
// 해당 쓰레드의 뮤텍스 소유를 해제하여 다른 쓰레드가 가질 수 있도록 한다.
 
HRESULT CloseHandle(HANDLE hHandle);
// 모든 커널 객체와 마찬가지로 생성된 뮤텍스를 파괴할 때 사용한다.
// 리턴 값 S_OK : 성공.
//           그외엔 에러.

* 포기된 뮤텍스

 만약 뮤텍스를 소유하고 있는 쓰레드가 ExitThread나 TerminateThread로 비정상적으로 종료시켰을 경우 강제로 뮤텍스를 시그널 상태로 만들어준다. 그러므로 대기 중인 다른 쓰레드에서 뮤텍스를 가지게 되는데, WaitForSingleobject() 의 리턴 값으로 WAIT_ABANDONED 값을 전달 받음으로써 이 뮤텍스가 정상적인 방법으로 신호상태가 된 것이 아니라 포기된 상태임을 알 수 있다. 중복 소유 뮤텍스를 여러 번 겹쳐서 사용했을 경우 데드락과 같은 상태에 빠질 수도 있을 것이다.

 

4. Semaphore

 - 뮤텍스와 유사한 동기화 객체이다. 뮤텍스는 하나의 공유 자원을 보호하는데 비해, 세마포어는 일정 개수를 가지는 자원을 보호할 수 있다. 여기서 자원이라는 것은 윈도우, 프로세서, 쓰레드와 같은 SW적이거나 어떤 권한과 같은 무형적인 것도 포함된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG iInitialCount,
                                      LONG iMaximumCount, LPCTSTR lpName);
// iMaximumCount는 최대 사용 개수.
// iInitialCount 에 초기값을 지정.
// 아주 특별한 경우외엔 이 두가지 값은 같다. 세마포어는 뮤텍스와 같이 이름을 가질 수 있고 이름을 알고 있는
// 프로세스는 언제든지 OpenSemaphore로 핸들을 구할 수 있다. 역시 파괴할 때는 CloseHandle 함수를 이용한다.
 
HANDLE OpenSemaphore(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSRT lpName);
// 뮤텍스와 같다.
 
BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG iReleaseCount, LPLONG lpPreviousCount);
// iReleaseCount로 사용한 자원의 개수를 알려준다. lpPreviousCount는 세마포어 이전 카운트를 리턴받기 위한
// 참조 인수이다. NULL 가능.

 

5. Event

 - 위의 동기화 객체들이 공유자원을 보호하기 위해 사용되는데 비해 이벤트는 쓰레드의 작업 순서나 시기를 조정하기 위해 사용된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
                             BOOL bInitialState, LPCTSTR lpName);
// bManualReset은 이벤트가 수동 리셋(쓰레드가 Non-Signaled로 만들어 줄 때 까지 신호 상태를 유지)인지
// 자동리셋(대기 상태가 종료되면 자동으로 Non-Signaled가 된다.) 인지를 결정한다. TRUE이면 수동이다.
// bInitialState가 TRUE이면 자동으로 Signaled 상태로 들어가 이벤트를 기다리는 쓰레드가 곧바로 실행할 수 있게 된다.
 
HANDLE OpenEvent(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSRT lpName);
// 다른 부분과 같다.
 
BOOL SetEvent(HANDLE hEvent);
// 다른 동기화 객체와는 다르게 사용자 임의로 Signaled 상태와 Non-Signaled 상태를 설정할 수 있다.
// 위의 함수는 Signaled 상태로 만들어 준다.
 
BOOL ResetEvent(HANDLE hEvent);
// Non-Signaled 상태로 만든다. 일반적으로 자동 리셋을 사용하는데, 이벤트를 발생시켜 대기 상태를 풀 때
// 자동으로 Non-Signaled 상태로 만드는 것이다. 하지만 여러 개의 쓰레드를 위해서 이벤트를 사용한다면
// 문제가 될 수도 있다. 그러므로 수동 리셋으로 이벤트를 생성 후 ResetEvent 함수로 수동리셋을 한다.

출처:: http://blog.daum.net/thermidor/5173637

Posted by 엘키 엘키

댓글을 달아 주세요


IT 얘기는 아닌거 같은데... 크게 공감되네요.

'General > Etc' 카테고리의 다른 글

상사와 부하의 상관관계  (0) 2013.11.22
정규표현식 정리  (0) 2013.10.10
Perl을 써보자~!  (0) 2010.01.28
Posted by 엘키 엘키

댓글을 달아 주세요

XML 예약문자

<, >, &는 XML tag 표시와 entity를 표시하는 XML 예약문자로, XML 문서에 그대로 사용할 수 없다.

< (less-than sign)&lt;
> (greater-than sign)&gt;
& (ampersand)&amp;



그리스문자

그리스 문자는 풀어서 사용한다.

αalpha
βbeta
γgamma
δ,Δdelta
εepsilon
ζzeta
ηeta
θtheta
ιiota
κkappa
λlambda
μmicron
νnu
ξxi
οomicron
πpi
ρrho
σ, Σsigma
τtau
υupsilon
φphi
χchi
ψpsi
ω, Ωomega



기호 & 부호

&lt; or =
&gt; or =
±+/-
˚degrees
degrees C
--&gt;
㎍, μGmicrogram
㎕, μLmicroliter
㎛, μMmicrometer
®(R)
(TM)
χ2chi─square



화학기호

화학기호는 윗첨자나 아랫첨자를 지정하지 않고 그대로 입력한다.

K+K+
Cl-Cl-
Mg2+Mg2+
CO2CO2
H2OH2O



수학기호

수학기호는 윗첨자나 아랫첨자를 괄호 "( )" 안에 넣어서 입력한다.

10210(2)
10-210(-2)
height2.239height(2.239)


'General > XML' 카테고리의 다른 글

XML 특수 문자 정리  (0) 2013.10.10
Posted by 엘키 엘키

댓글을 달아 주세요


블로그 이미지
Software Engineer
엘키

공지사항

Yesterday31
Today27
Total1,605,481

달력

 « |  » 2020.8
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          

글 보관함