멀티 코어 시대인 만큼 요즘은 프로그램들을 평가할 때 멀티코어를 얼마나 잘 활용하나를 중요하게 따집니다. 그래서 프로그래밍 언어나 라이브러리에서 병렬 프로그래밍 지원을 하는 경우가 많습니다. C++11에서도 큰 특징 중의 하나가 thread 라이브러리 지원입니다.

 

VC의 경우는 현재 사용 중인 10에서는 MS 독자의 Concurrency Runtime을 지원하였고, 이번 버전에서는 C++ 표준의 thread 라이브러리를 제공합니다(VC 전용으로 GPGPU 프로그래밍을 위해 AMP 라이브러리도 제공합니다).

 

C++11 thread 라이브러리를 사용하면 기존에 복잡하고, 플랫폼 마다 다르게 기술해야 하는 스레드 프로그래밍을 쉽고, 플랫폼 독립적으로 구현할 수 있습니다.

 

앞으로 몇 번에 걸쳐서 C++11 thread를 다룹니다. 내용이 어렵지 않으니 천천히 따라오시면 됩니다. thread 라는 것이 무엇인지는 책이나 인터넷을 통해서 미리 공부하시기 바랍니다. 따로 thread에 대한 이론 설명을 하지 않겠습니다. ^^;

 

 

 

thread 생성하기

 

thread 라이브러리를 사용하기 위해서는 아래의 헤더 파일을 포함해야 합니다.

#include <thread>

 

thread 클래스의 생성자는 아래와 같습니다.

thread() _NOEXCEPT;

 

template<class Fn, class... Args>

   explicit thread(Fn&& F, Args&&... A);

 

thread(thread&& Other) _NOEXCEPT;

 

 

인자 중 Fn은 생성된 스레가 호출할 함수(애플리케이션에서 정의한), A Fn에 넘겨 줄 인수 리스트, Other는 기존의 스레드 오브젝트 입니다.

 

첫 번째 생성자는 thread 오브젝트는 만들지만 실제 스레드(OS에서 만들어진 스레드)와는 연결되지 않습니다.

두 번째 생성자는 실제 스레드와 연결된 오브젝트를 생성합니다. 만약 충분한 리소스가 없어서 스레드를 시작할 수 없다면 system_error 오브젝트에 resource_unavailable_try_again 에러코드로 예외를 발생시킵니다.

세 번째 생성자는 다른 thread 오브젝트를 넘겨 받아서 오브젝트를 생성합니다. 인자가 우측 값 참조 이므로 이후에 Other에 연결된 스레드는 Other과 연결이 끊어집니다.

 

아래의 예제를 통해서 스레드를 어떻게 사용하는지 보겠습니다.

 

< 예제. 1 >

#include <thread>

#include <iostream>

 

int main()

{

           std::thread Thread1( [] ()

                        {

                                   for( int i = 0; i < 5; ++i )

                                   {

                                          std::cout << "Thread Num : " << i << std::endl;

                                   }

                      } );

 

 

           std::thread Thread2;

           Thread2 = std::thread( [] ()

                        {

                                    for( int i = 10; i < 15; ++i )

                                   {

                                          std::cout << "Thread Num : " << i << std::endl;

                                   }

                         } );

 

           std::thread Thread3 = std::thread( [] ( int nParam )

                        {

                                 for( int i = 20; i < 25; ++i )

                                 {

                                    std::cout << "Thread Parameter : " << nParam << std::endl;

                                 }

                            }, 4 );

 

          

 

           getchar();

           return 0;

}

 

< 결과 >


위 결과를 보면 스레드가 3개 만들어져서 실행된 것을 알 수 있습니다. 그런데 첫 번째 줄에 출력된 결과가 이상하죠? 이것은 공유 객체를 동기화 하지 않아서 발생한 것입니다. 이것은 뒤에 동기화 객체를 설명할 때 고쳐 보겠습니다^^;




ps: 위의 소스는 완벽한 것이 아닙니다. 아마 실행하면 에러가 발생할 것입니다. 이와 관련된 글은 뒤에 적을 글에서 설명할 예정이라서 이번 글의 코드에서는 일부러 조금 불완전한 코드를 사용했습니다.^^;;;


by 흥배 2012. 11. 12. 09:00
  • hkskyp 2012.11.12 15:13 ADDR EDIT/DEL REPLY

    이번 코드를 실행 시켜보니까 abort()가 발생하던데요.
    그래서 저는 join()를 추가 했습니다. 혹시 abort()가 발생하지 않았나요?

    Thread1.join();
    Thread2.join();
    Thread3.join();

    • 흥배 2012.11.12 16:23 신고 EDIT/DEL

      네 에러가 발생하는 것이 맞습니다. 관련된 글을 뒤에 올릴 예정이라서 따로 언급하지 않았는데 오해를 줄 수 있겠네요. 글 수정하겠습니다.^^;

  • 저.. 2013.12.11 16:33 ADDR EDIT/DEL REPLY

    #include <thread>에 빨간줄 뜨면서 파일 소스를 열 수 없다고 나오는데요...왜그럴까요ㅠㅠㅠ??

    • 흥배 2013.12.12 14:21 신고 EDIT/DEL

      혹시 컴파일도 안되나요? 컴파일은 되는데 그런경우라면 보통 컴퓨터 성능이 VS가 원하는 것보다 낮아서 실시간으로 체크를 못해서 나타나는 현상입니다. VS2012 버전 이상에서는 thread 사용할 수 있습니다.

  • 머드게임 개발중... 2014.11.11 20:17 ADDR EDIT/DEL REPLY

    VS2010에서 thread 쓰려니까 진짜 죽겠더군요.
    결국 VS2013깔고 thread 공부중입니다.
    설명이 잘돼있네요 굿굿

    • 흥배 2014.11.11 23:15 신고 EDIT/DEL

      ㅎㅎ 즐거운 프로그래밍 하세요^^

올해 2월에 MSHerb Sutter씨는 VC11의 생각보다 빈약한 C++11 기능 지원에 대해서 앞으로 나머지 기능을 업데이트를 통해서 추가해 나갈 것이라고 이야기했습니다.

 

이번에 이 약속이 거짓이 아님을 보여주는 것이 나왔습니다.^^

 

VS 2012 CTP(Community Tech Preview)가 나왔는데 여기에 VS2012에 없는 C++11 기능이 추가 되었습니다.

다운로드 http://www.microsoft.com/en-us/download/details.aspx?id=35515

 

새로 추가된 기능은 아래와 같습니다.

Variadic templates

Uniform initialization and initializer_lists

Delegating constructors

Raw string literals

Explicit conversion operators

Default template arguments for function templates

 

저는 특히 Variadic templatesUniform initialization and initializer_lists가 추가된 것이 무척 반갑습니다. 이후에도 업데이트 버전이 나올 수 있는데 그때는 꼭 constexpr이 구현되면 좋겠습니다. constexpr을 사용하면 기존에 매크로나 템플릿을 사용하여 구현한 부분을 대체하여 더 좋은 성능을 더 쉽게 낼 수 있을 것 같습니다.

 

VS 2012 CTP는 정식 버전은 아니기 때문에 설치 후 사용하기 위해서 약간 손을 봐야 합니다.

프로젝트 속성에서 '일반' -> '플랫폼 툴셋'을 선택하여 ' Microsoft Visual C++ Compiler Nov 2012 CTP (v120_CTP_Nov)'을 선택해야 합니다.

 

좀 더 자세한 설명은 http://blogs.msdn.com/b/vcblog/archive/2012/11/02/visual-c-c-11-and-the-future-of-c.aspx 를 봐 주세요

by 흥배 2012. 11. 3. 20:45

아래 코드에서 TEST1은 몇 번 생성될까요?


TEST1 GetTest1_1()

{

           TEST1 test1;

           test1.nValue = 11;

 

           return test1;

}

 

int main()

{

           ....

           auto test1_1 = GetTest1_1();

           ....

}

 

위의 코드를 실행하면 main에서 TEST1 객체 생성(1), GetTest1_1() 함수에서 TEST1 객체 생성(2)에 의해 TEST1은 총 2번 만들어집니다.

 

그러나 실제로는 C++ 최적화(즉 릴리즈모드로 컴파일 하면)에 의해 TEST1 객체는 한번만 생성합니다. 위의 최적화를 NRVO라고 합니다(RVO도 있습니다).

 

그런데 NRVO는 한계가 있습니다. 아래와 같은 경우에서는 NRVO 최적화를 사용할 수 없습니다.

 

TEST1 GetTest1_2( int nTemp )

{

           TEST1 test1;

           test1.nValue = 11;

 

           if( nTemp > 100 )

           {

                     test1.nValue = 111;

                     return test1;

           }

 

           return test1;

}

 

코드를 보면 알겠지만 TEST1 객체를 조건문에 의해서 다르게 반환하는 경우 컴파일러는 NRVO 최적화를 하지 않습니다.

 

이때는 C++11 move 생성자를 사용하여 최적화를 할 수 있습니다.

 

C++11에서는 GetTest1_2와 같은 상황일 때 TEST1move 생성자를 정의해 놓으면 컴파일러가 move 생성자를 사용합니다.

당연하겠지만 move 생성자를 정의하고 있어도 NRVO를 사용할 수 있으면 NRVO 최적화를 최우선적으로 사용합니다.

 

 

< 예제 코드 >

#include <iostream>

 

struct TEST1

{

           int nValue;

 

           TEST1()

           {

                     std::cout << "TEST1 생성자" << std::endl;

           }

          

           ~TEST1()

           {

                     std::cout << "TEST1 소멸자" << std::endl;

           }

 

           TEST1(const TEST1& obj)

           {

                     nValue = obj.nValue;

 

                     std::cout << "TEST1 복사 생성자" << std::endl;

           }

};

 

struct TEST2

{

           int nValue;

 

           TEST2()

           {

                     std::cout << "TEST2 생성자" << std::endl;

           }

          

           ~TEST2()

           {

                     std::cout << "TEST2 소멸자" << std::endl;

           }

 

           TEST2(const TEST2& obj)

           {

                     nValue = obj.nValue;

 

                     std::cout << "TEST2 복사 생성자" << std::endl;

           }

          

           TEST2(TEST2&& obj)

           {

                     nValue = obj.nValue;

 

                     std::cout << "TEST2 move 생성자" << std::endl;

           }

};

 

 

TEST1 GetTest1_1()

{

           TEST1 test1;

           test1.nValue = 11;

 

           return test1;

}

 

TEST1 GetTest1_2( int nTemp )

{

           TEST1 test1;

           test1.nValue = 11;

 

           if( nTemp > 100 )

           {

                     test1.nValue = 111;

                     return test1;

           }

 

           return test1;

}

 

TEST2 GetTest2_1()

{

           TEST2 test2;

           test2.nValue = 11;

 

           return test2;

}

 

TEST2 GetTest2_2( int nTemp )

{

           TEST2 test2;

           test2.nValue = 11;

 

           if( nTemp > 100 )

           {

                     test2.nValue = 111;

                     return test2;

           }

 

           return test2;

}

 

int main()

{

           std::cout << "TEST1 - NRVO 사용" << std::endl;

           {

                     auto test1_1 = GetTest1_1();

           }

 

           std::cout << std::endl;

          

           std::cout << "TEST1 - NRVO 사용 불가" << std::endl;

           {

                     auto test1_2 = GetTest1_2(101);

           }

 

           std::cout << std::endl;

           std::cout << std::endl;

          

           std::cout << "TEST2 - NRVO 사용" << std::endl;

           {

                     auto test2_1 = GetTest2_1();

           }

 

           std::cout << std::endl;

          

           std::cout << "TEST2 - move 생성자 사용" << std::endl;

           {

                     auto test2_2 = GetTest2_2(101);

           }

 

          

           return 0;

}

 

< 결과 >


by 흥배 2012. 10. 24. 09:30

range base for는 다 좋은데 조금 아쉬운 부분이 있습니다.

그것은 앞에서 뒤로 순차적으로만 접근이 된다는 것입니다.

때로는 뒤에서부터 시작해야 할 때가 있습니다.

 

이때는 일반적인 방법으로는 안되고 boost 라이브러리의 도움을 받으면 할 수 있습니다.

boost 라이브러리의 boost::adaptors::reverse 를 사용합니다.

 

< 예제. 4 >

#include <iostream>

#include <boost/range/adaptors.hpp>

 

int main()

{

           int NumberList[] = { 1, 2, 3 };

 

           for (auto i : boost::adaptors::reverse(NumberList))

           {

                     std::cout << i << "  ";

           }

 

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

 

 

 

           std::vector<int> vecNumberList;

           vecNumberList.push_back( 1 );

           vecNumberList.push_back( 2 );

           vecNumberList.push_back( 3 );

 

           for (auto i : boost::adaptors::reverse(vecNumberList))

           {

                     std::cout << i << "  ";

           }

 

           std::cout << std::endl;

 

           return 0;

}

 

< 실행 결과 >


by 흥배 2012. 10. 15. 09:00

range base for에서 데이터셋의 요소를 변경할 수 있을까요?

정답은 있을 수도 있고, 없을 수도 있습니다.

 

앞 선 예제 코드에서는

for( auto i : NumberList )

이런 식으로 사용했는데 이런 경우 i의 값을 for 문 안에서 변경 할 수 있지만 for 문을 나오면 NumberList의 요소에는 적용되지 않습니다.

 

만약 요소의 값을 변경하고 싶다면 참조를 사용하면 됩니다.

for( auto &i : NumberList )

이런 식으로 하면 for 문을 나와도 NumberList의 요소는 변경이 적용되어 있습니다.

 

그런데 만약 for 문에서 요소 값을 변경하지 못하도록 하려면 const를 사용합니다.

for( auto const i : NumberList )

 

for 문에서 데이터셋 요소를 접근할 때는 임시 변수를 만들기 때문에 이 비용을 줄이고 싶다면 참조를 사용하면 좋습니다.

또 만약 요소의 값을 변경하지 못하도록 하고 싶다면 const 참조를 사용합니다.

for( auto const &i : NumberList )

 


< 예제. 3 >

#include <iostream>

#include <vector>

 

int main()

{

           std::vector<int> NumberList;

           NumberList.push_back( 1 );

           NumberList.push_back( 2 );

           NumberList.push_back( 3 );

          

           for( auto i : NumberList )

           {

                     std::cout << i << " * 10 : ";

 

                     i *= 10;

                     std::cout << i << std::endl;

           }

 

           for( auto i : NumberList )

           {

                     std::cout << i << "  ";

           }

          

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

 

 

           for( auto &i : NumberList )

           {

                     std::cout << i << " * 10 : ";

 

                     i *= 10;

                     std::cout << i << std::endl;

           }

 

           for( auto i : NumberList )

           {

                     std::cout << i << "  ";

           }

 

           std::cout << std::endl;

 

           return 0;

}

 

< 실행 결과 >




by 흥배 2012. 9. 26. 01:07
  • leafbird 2012.09.26 13:12 신고 ADDR EDIT/DEL REPLY

    아 이거 좋네요 +_+ 제가 알기론 vc++ 비표준 키워드 for each는 값을 변경할 수 있는 방법이 없었던 거 같은데

너무 당연한 것이지만 range base for에는 배열 뿐만이 아닌 STL의 컨테이너들도 사용할 수 있습니다.

아래 예제를 통해서 STL 컨테이너를 range base for문에서 어떻게 사용하는지 보겠습니다.

 

< 예제. 2 >

#include <iostream>

#include <vector>

#include <unordered_map>

#include <string>

 

int main()

{

           std::cout << "range base for - vector" << std::endl;

 

           std::vector<int> NumberList;

           NumberList.push_back( 1 );

           NumberList.push_back( 2 );

           NumberList.push_back( 3 );

          

           for( auto i : NumberList )

           {

                     std::cout << i << std::endl;

           }

           std::cout << std::endl;

 

 

 

           std::cout << "range base for - unordered_map" << std::endl;

 

           std::unordered_map<int, std::string> NumString;

           NumString.insert( std::make_pair<int, std::string>(1, "1") );

           NumString.insert( std::make_pair<int, std::string>(2, "2") );

           NumString.insert( std::make_pair<int, std::string>(3, "3") );

 

           for( auto i : NumString )

           {

                     std::cout << "key : " << i.first << ", value : " << i.second << std::endl;

           }

 

           std::cout << std::endl;

 

           return 0;

}

 

< 실행 결과 >


 

 

range base for문은 기본적으로 STL의 이터레이터를 지원하는 컨테이너라면 문제 없이 사용할 수 있습니다. 그러므로 프로그래머가 자신만의 컨테이너를 만든다면 STL에서 정의한 이터레이터의 기능을 구현하면 range base for 문을 사용할 수 있습니다.

 

이전에는 STL 컨테이너의 모든 요소를 반복문에서 사용할 때  for_each를 사용했는데 사용하기 위해서 준비해야 할 것이 많았는데 VC10에서 lambda 덕분에 쉬워졌습니다. 그러나 range base for 문과 비교해보면 for_each+lambda 보다는 range base for 문이 더 사용하기 편한 것을 알 수 있습니다.

 

이제 VC11부터 for 반복문은 꼭 range base for를 사용하기 바랍니다^^

by 흥배 2012. 9. 21. 13:01
  • 웅이 2015.02.22 23:11 ADDR EDIT/DEL REPLY

    공부하는 사람인데요. 궁금한게 있어서 여기 문의 드립니다.
    비쥬얼 2013에서 빨간줄을 보여주고 있습니다..(그런데 컴파일해서 실행하면 잘됨,,,)
    마우스 커서를 가져대면 인수 목록이 일치하는 함수 탬플릿 std::make_pair의 인스턴스가 없습니다 인수형식이 (int, const char[2])입니다. 라고 뜨는데.
    컴파일 잘되니 에러는 상관없는건가요?

    • 흥배 2015.02.23 22:51 신고 EDIT/DEL

      네 컴파일 잘 된다면 문제 없을 것 같네요

VC10에서 선보였던 C++11의 기능 중 강력하면서 사용하기 쉽고, 자주 사용한 기능이 아마 'auto'이지 않을까 생각합니다. 예전에 강연을 할 때 auto와 관련된 예제를 보여드리면 많은 분들이 아주 좋아하시더군요(좀 놀라기도 하시더군요^^). 어떤 분들은 딴 건 제쳐두고 이것 때문이라도 VC10을 사용해야겠다는 분들이 있었습니다.

 

이번 VC11에서도 'auto'와 같은 강력한 기능이 있습니다. 바로 'range base for' 입니다. 이것을 사용하면 반복문을 아주 쉽고, 강력하게 사용할 수 있습니다.

VC 특화 기능인 for each와 비슷하기 때문에 기존에 for each를 사용하고 있다면 이제는 range base for로 쉽게 바꾸어서 사용하면 됩니다.

 

 

예제를 통해 일반적인 for , VC for each, range base for문의 차이를 예제를 통해서 보겠습니다.

 

< 예제. 1 >

#include <iostream>

  

int main()

{

           int NumberList[5] = { 1, 2, 3, 4, 5 };

 

          

           std::cout << "일반적인 for " << std::endl;

          

           for( int i = 0; i < 5; ++i )

           {

                     std::cout << i << std::endl;

           }

 

 

           std::cout << "VC++ 특화의 for each" << std::endl;

 

           for each( int i in NumberList )

           {

                     std::cout << i << std::endl;

           }

 

 

           std::cout << "range base for " << std::endl;

 

           for( auto i : NumberList )

           {

                     std::cout << i << std::endl;

           }

 

           return 0;

}

 


< 실행 결과 >


 


<예제.1>을 보면 일반적인 for 문은

for( int i = 0; i < 5; ++i )

와 같이 시작과 종료 조건, 증가 값 이렇게 3개의 조건에 의해서 반복 됩니다.

 

그러나 range base for문은 VC만의 반복문인 for each와 비슷하게 데이터셋 변수와 이 데이터셋 요소의 타입을 선언하면 됩니다.

for( auto i : NumberList )

 

기존의 for 문에 비해서 또는 for each 보다도 간편해졌고, for each는 표준이 아닌 VC만의 기능인 것에 비해서 range base for C++ 표준 기능입니다.

 

range base for 문의 문법은 아래와 같습니다.

for ( for-range-declaration : expression ) statement

 

 

range base for 덕분에 반복문의 사용이 쉬워졌고, for 문을 사용할 때 종료 조건이 잘못되어 메모리 침범을 하는 위험도 피할 수 있게 되었습니다.

by 흥배 2012. 8. 29. 09:00

Placement Insert C++11의 기능 중에 하나로 STL 컨테이너와 관계가 있습니다.

VC11 Placement Insert를 지원합니다. 만약 이 기능을 VC10 이하에서 사용하고 싶다면 Boost 라이브러리의 컨테이너를 사용하면 됩니다. 


struct ITEM

{

ITEM( int nCode )

{

}

};

 

std::vector< ITEM > Items;

 

Items.push_back( ITEM( 1 ) );

 

 

현재까지는 위 코드처럼 ITEM이라는 객체를 Items 컨테이너에 생성과 동시에 추가를 할 때는 위와 같이해야 합니다. 그런데 위 방식으로 하면 추가를 위해 컨테이너에 한번 생성을 한 후 복사를 해야 하는 문제가 발생합니다(또 임시 객체 만들므로 삭제 비용도 발생합니다).

 

이와 같은 동작은 우리가 원하는 것이 아닙니다.

 

그래서 C++11에서는 이와 같은 문제를 해결했습니다. 바로 ‘Placement Insert’가 해결했습니다.

 

C++11 ‘Placement Insert’를 사용하면 위의 코드는 아래와 같이 할 수 있습니다.

 

std::vector< ITEM > Items;

 

Items.emplace_back( 1 );

 

emplace_back push_back과 같지만 Placement Insert 기능이 구현된 것으로 임시 오브젝트를 만들면서 발생하는 비용을 없애줍니다.

 

C++11의 각 컨테이너에는 Placement Insert와 관련된 멤버로

emplace(insert),

emplace_back(push_back),

emplace_front(push_front),

emplace_hint(insert. 연관 컨테이너 용)

가 추가됩니다.

 

Placement Insert C++11의 새로운 기능인 가변 인수 템플릿을 사용하여 구현되었습니다.

 


Placement Insert는 아래와 같은 주의할 점도 있습니다.

 

1. explicit 문제.

   explicit 생성자도 암묵적으로 호출됩니다.

 

2. "0" 문제.

생성자의 파라미터가 포인터인 경우 인자로 0을 넘기면 int로 추론합니다. 그래서 이 경우에는 nullptr을 사용해야 합니다.

by 흥배 2012. 8. 27. 09:00

이번은 chrono clock 클래스에 대해서 간단하게 설명 하겠습니다.

앞의 글들을 보신 분 들은 아시겠지만 이미 clock 클래스를 사용하고 있었습니다.

 

다만 저는 현재까지는 system_clock 이라는 클래스만을 사용하고 있었습니다.

 

chrono에는 system_clock뿐만 아닌 steady_clock high_resolution_clock이 있습니다.

 

 

namespace std {

 

namespace chrono {

 

  class system_clock;

 

}}

 

 

namespace std {

 

namespace chrono {

 

  class steady_clock;

 

}}

 

   

 

namespace std {

 

namespace chrono {

 

  class high_resolution_clock;

 

}}

 

 

system_clock는 가장 일반적으로 사용하는 것으로 시스템 시간을 표현하기 위한 시간입니다.

그리고 C 런타임의 time_t와 호환성을 가지고 있습니다.

 

멤버 중에 to_time_t from_time_t가 있는데 이름을 보면 알 수 있듯이

to_time_t system_clock::time_point time_t로 변환하고,

from_time_t time_t system_clock::time_point로 변환 합니다.

  

// to_time_t

system_clock::time_point CurTime = system_clock::now();

std::time_t t = system_clock::to_time_t(CurTime);

 

// from_time_t

std::time_t t = time(NULL);

system_clock::time_point CurTime = system_clock::from_time_t(t);

 

steady_clock은 물리적인 시간처럼 결코 역행하지 않는 시간을 나타내기 위한 시간입니다.

이 말은 steady_clock 이외의 clock 클래스는 time_point를 얻은 후 os에서 날짜를 과거를 되돌린 후 time_point을 얻으면 앞에 얻은 시간보다 과거의 시간이 얻어지는데 steady_clock에서는 절대 그렇지 않습니다. 그래서 시간의 흐름이 바뀌지 않는 시간을 얻고 싶을 때는 steady_clock을 사용합니다.

 

 

high_resolution_clock는 해당 플랫폼(Windows 또는 Linux )에서 가장 짧은 단위의 시간입니다.

이 클래스는 system_clock steady_clock의 다른 별칭으로 정의되기도 합니다.

 

 

 

보통 프로그래밍에서 아주 고해상도의 시간 단위가 아닌 경우 대부분 GetTickCount() 함수를 사용했는데(Windows에서) 앞으로는 더 간단하고 다양한 표현 방법으로 시간을 다룰 수 있는 chrono를 꼭 사용해 보시기 바랍니다^^

by 흥배 2012. 8. 16. 09:00

<예제.2>에서 보았듯이 chrono는 다양한 정밀도 타입으로 시간을 표시할 수 있습니다.

 

그리고 각 시간 정밀도 타입 별로 생성할 때 미리 값을 설정할 수 있습니다.

 

std::chrono::hours H1(1);

std::chrono::seconds S1(10);

std::chrono::milliseconds MILS1(100);

 

또한 이 시간 타입을 서로 연산할 수도 있습니다.

 

std::chrono::hours H1(1);

std::chrono::hours H2(2);

std::chrono::hours H3 = H1 + H2;

 

물론 다른 시간 타입을 연산할 수도 있습니다

 

std::chrono::seconds S1(10);

std::chrono::milliseconds MILS1(100);

std::chrono::milliseconds MILS2 = S1 + MILS1;

 

다른 시간 타입을 연산할 때 주의할 점이 있습니다. 아래처럼

 

std::chrono::milliseconds MILS2 = S1 + MILS1;

 

의 경우는 초와 밀리초라는 서로 다른 타입을 더하지만 값을 저장하는 타입이 밀리초이기 때문에 잃어버리는 값이 발생하지 않으므로 연산에 문제가 없습니다.

그러나 아래와 같이

std::chrono:: seconds S2 = S1 + MILS1;

로 하는 경우는 밀리초 부분을 잃어버리게 되기 때문에 컴파일 에러가 발생합니다.

 

이런 경우는 명시적으로 형 변환을 시켜줘야 합니다.

std::chrono::seconds S2 = std::chrono::duration_cast< std::chrono::seconds >(S1 + MILS1);

 

 

< 예제. 3 >

#include <chrono>

#include <iostream>

 

int main()

{

    {

        std::chrono::hours H1(1); // 1시간

       

        std::cout << "H1(1) : " << H1.count() << std::endl;

        

        std::chrono::seconds S1(10);

        std::chrono::seconds S2(120);

 

        std::cout << "S1(10) : " << S1.count() << std::endl;

        std::cout << "S2(120) : " << S2.count() << std::endl;

    }

 

    {

        std::chrono::hours H1(1);

        std::chrono::hours H2(2);

        std::chrono::hours H3 = H1 + H2;

 

        std::cout << "H1 + H2 = : " << H3.count() << std::endl;

  

        std::chrono::seconds S1(10);

        std::chrono::milliseconds MILS1(100);

        std::chrono::milliseconds MILS2 = S1 + MILS1;

 

        std::cout << "S1 + MILS1 = : " << MILS2.count() << std::endl;

  

        std::chrono::seconds S2 = std::chrono::duration_cast< std::chrono::seconds >(S1 + MILS1);

 

        std::cout << "S1 + MILS1 = : " << S2.count() << std::endl;

    }

 

    return 0;

}

 


<
실행 결과 >



by 흥배 2012. 8. 9. 09:00
| 1 2 3 |