본문 바로가기

기술자료/CPP

멀티스레드 강좌 2



 The Boost.Threads Library


 


다들 안녕하셨습니까 ^^;


봄비가 오는군요 .... 이제
곧 파릇파릇하게 돋아나는 새싹을 볼 수 있을거 같아 벌써부터


마음이 설레입니다.


 


이번 이야기에서는 저번에
언급했던 거처럼 함수-객체(Function Object)와


함수 어댑터(Function Adapter)에
대해서 알아 보고자 합니다. 후흣... 영어군요 -_-;;


오~~ 웬지 어려워 보이고
대단해 보이기도 합니다 -_-;;


 


자 그럼 일단 함수-객체를
설명하고자 하는 이유부터 설명해야 순서가 맞을 거 같습니다.


DWORD WINAPI
MyNameIsThread (void* lPram);


 


어디서 많이 본듯한 함수
원형입니다......... 아 맞다 ! ........... -_-ㆀ


쓰레드 함수..가 저런 모양이지
!!


네 맞습니다. 맞고요 -_-;
(한번 해보고 싶었습니다 ㅜㅜ;)


 


위의 함수 선언과 같이 우리는
쓰레드 안쪽으로 우리가 원하는 데이터를 전달하기 위해서 void* 형을 활용합니다.


기억이 가물가물한 분들을
위해서 ^_^;;


 


DWORD WINAPI
MyNameIsThread (void* lPram)


{


    CFerrari*
pFerrari = static_cast< CFerrari*>(lPram);


    pFerrari->GetPrice();


    ……………………


}


헉! 위의 코드가 생소하십니까
?  저와 ... 똑같으시군요 -_-;;


 


하지만 Boost Threads Library에서는
이러한 컨셉을 사용하지 않고 함수-객체라는 컨셉을 사용한답니다.


즉 쓰레드 안쪽으로 우리가
원하는 데이터를 전달하기 위해서 함수-객체를 사용한다는 말입니다.


 


자 이제 그럼 함수-객체에
대해서 알아봐야 할 때가 된 거 같습니다.


그들이 오고 있다.............
두~둥 ~! -_-;;


 


함수-객체………


일단 이름에서 느껴지듯이
함수처럼 행동하는 객체입니다 -_-;


그럼 함수처럼 행동한다는
것은 무엇을 의미할까요 ?


 


bool nResult
= DoIt(“Ferrari”, 405);


 


음.... 위의...Doit ...........
함수...... 같아 보입니다 ^0^; 동의 하시지요 ?


왜 동의하셨습니까 ?


 


제가 보기엔 일단 괄호를
사용하여 인자를 전달할 수 있고..


그리고 괄호를 사용하여 호출할
수 도 있고.. 그리고 반환값도 있는 거 같습니다.


그래서 저는 함수라고 판단했습니다.


 


자 이제 우리가 해야 할 일은
저런 행동을 똑같이 하면서 그걸 객체로 만들어 내기만 하면 됩니다.


어떻게 ? ……… 다음과 같이
말입니다 ^_^;


 


class CPrintCarName


{


public:


    void
operator() (std::string strCarName) const


    {


        std::cout
<< strCarName << std::endl;


    }


};


 


자 이제 우리가 ……


CPrintCarName
printCarName;


printCarName(“FerrarI”);


라고 하였다면 이것은 내부적으로
다음과 같이 호출하는 것입니다.


 


printCarName.operator()
(“FerrarI”);  // 오 ~~ 이해가 조금 된다 @_@;


 


자 그럼 결과적으로 봐서..
printCarName(“FerrarI”) 함수 같아 보이십니까 ?


제 눈엔 함수같아 보입니다.
여러분 눈에도 그렇게 보일것라고 생각합니다.


 


네... 이런 것이 바로 STL의
컨셉입니다 : Generic Programming , Pure Abstraction


즉 함수처럼 행동하는 모든
것은 함수입니다.


 


바로 이러한 함수-객체들이
STL 알고리즘의 인자로 전달됨으로써 알고리즘의 동작을 무한히 확장시키실 수 있습니다.


헉!! 무한 확장 ..............
아트입니다 ㅠ_ㅠ;


 

More C++ Gems
by Rober C. Martin, ISBN :
0521786185  p.97
페이지 "Open - Closed Principle"


보신적이 있으십니까 ? 물론
저도 못봤습니다.. 하지만 .. 장담 할 수 있는건


STL이 바로 “Open - Closed
Principle”의 가장 대표적인 예일 것이라는 점입니다.


 


즉 확장성에 대해서는 Open
정책을 취하지만, 기존의 형태를 수정하는 것에 대해서는 Closed 정책을 취한다는
의미입니다.


 


그럼 이제 가장 원론적이면서도
오늘 정환군이 가장 하고 싶었던 이야기를 해보고자 합니다. 참 서론이 길었습니다
..


결정적으로 .. 함수-객체가
함수에 비해서 모가 좋을까요 -_-;


오히려 비슷한 행동을 하면서
코딩량만을 늘어나면서 말이지 -_-;;


 


 


..........................
정적이 흐릅니다. 자 다들 명상의 시간을 -_-ㆀ


 


 


 


자 이렇게 생각해 보면 어떨까요
?


Function VS Class 어느 쪽에
손을 들어주시겠습니까 ?


음 기우뚱 하신다면 template
class를 생각해 보시면 어떻습니까 ?


 


네 그렇습니다...


한마디로 함수-객체는“Smart
Function”이라고 생각할 수 있습니다.


부가적인 멤버 함수를 가질
수 있을 뿐만 아니라 자신만의 타입을 가질 수도 있습니다.


이러한 점들은 기존의 함수에서는
불가능 한 점들이랍니다. 오~~~ @_@; 좋고 ~!


 


자.. 이제 우리의 메인
주제인 boost::Thread로 돌아갈 시간이 된거 같습니다.


 


std::fstream이 플랫폼에
상관없이 파일과 관련된 작업을 랩핑하였듯이


boost::thread클래스도 플랫폼에
상관없이(POSIX, Win32, Macintosh Carbon) 쓰레드와 관련된 작업을 랩핑하고 있습니다.


 


boost::thread의 디폴트 생성자에서는
현재 쓰레드를 대표하는 인스턴스를 생성합니다.


그리고 오버로딩된 생성자에서는
인자와 반환값이 없는 함수-객체를 인자로 가지고 있습니다.


이 생성자에서는 새로운 쓰레드를
시작하게 됩니다.


 


위에서도 설명하였듯이 이
인자로 들어온 함수-객체를 사용하여 쓰레드 안쪽으로 우리가 원하는 데이터를 전달하게
됩니다.


물론 기존의 방식에 익숙한
사용자들은 이러한 방법이 처음에는 불편할지도 모르겠지만 익숙해 진다면 예전보다
손쉽게 전달할 수 있습니다.


그리고 이러한 접근 방식은
보다 높은 유연성과 타입 안정성을 제공해 준답니다.


 


이 뿐만 아니라 Boost.Bind와
같은 유틸리티적인 라이브러리와 결합하게 된다면


더욱 편리한 방식으로 쓰레드쪽으로
필요한 데이터를 전달해 줄 수 있답니다.


음 -_-;;; Oooops....  필이
안 옵니다 ㅠ_ㅠ;


 


자 다음의 샘플과 함께 비교하면서
위의 말들은 다시 한번 읽어보면 어떨까요 ^-^;


 










Sample No 1
: The Boost::thread Class



#include <boost/thread/thread.hpp>


#include <iostream>


#include <string>


 


struct Message


{


    Message(std::string
strVendor) : m_strVendor(strVendor) {}


    


    void
operator() ()  // 인자와 리턴값이 없는 함수-객체


    {


        std::cout
<< “
Hello” << m_strVendor << std::endl;


    }


    


    std::string
m_strVendor;


}


 


int main ()


{


    boost::thread
messageThrd(Message(“Devpia”));


    messageThrd.join();


    return
0;


}



 


“sample 1”에서는“Hellow
Devpia”를 출력하는 새로운 쓰레드를 생성합니다.


boost::thread
messageThrd(Message(“Devpia”));


 


그리고 main 함수에서는 boost::thread::join을
호출하므로써 messageThrd 쓰레드가 완료될 때까지 대기하게 됩니다.


messageThrd.join();


 


그리고 나서 main 함수가
종료됩니다.


오~~~~~!!!  쓰레드
끝날때 까지 대기하는 코드까지 .. !


코드 상큼하고... 예쁘고
귀엽고 빙고 ~~~!  -_-;;


 


자 .. “sample 1”예제에서
보여진 messageThrd를 Boost.Threads의해서 생성된 "쓰레드 객체"라고
부릅니다.


그리고 Boost.Threads에서는
아직까지 이 "쓰레드 객체"에 대해서 단 2가지 동작만을 지원하고 있습니다.


 


바로 생성된 쓰레드 객체가
같거나 다름을 판단해 주는 !=, ==오퍼레이터뿐입니다.  


예를 들어


 


if (messageThrd
== messageThrd)


{


    std::cout
<< "Thread object Same !" << std::endl;


}


지금은 단 2개..........
그러나 이 사실은 머지않아 변경될 것입니다.


 


어떠십니까 ? Boost::Threads
Library ...........


매력적이십니까 ?


 


다음 이야기에서는 Boost::Threads
Library의 꽃인 Mutex, Condition Variable


에 대해서 이야기해봤으면
합니다.


 


To be continue ...


 


 


참고 문헌


: http://boost.org/libs/thread/doc/index.html


: C / C++ Users Journal


: The C++ Standard library a Tutorial and Reference


 


작성자


: 냐옹이 정환군 (191cm@korea.com.no_spam)


 


PS>


나는 지식을 암기하기 위해 내 두뇌를 쓰고싶진 않다.
단순히 지식을 저장하기 위한 용도라면 
컴퓨터 하드디스크 보다 더 나을것이 없을지도 모른다.
늦은 퇴근길에 지하철 역사에서 듣는 이름모를 교향곡을
음미하며 온몸의 세포들을 그 음률에 맏기거나
내 앞에선 사람의 아름다움을 발견하는 용도로써,
신체 기능이 멈춰 더이상 뇌에 산소공급이 멈출때 까지
그렇게 두뇌를 쓰고 싶다.
책에 녹아있는 지식을 음미하고 이해했다면
그것을 부여잡고 영원토록 남겨두고 싶지는 않다.
그래서인지 나는 대학 성적표를 F로 장식했고
공부 못한다는 소리를 자주 듣는지도 모른다.


 


- 태권브이