Visual Studio 2010 공식 팀 블로그 @vsts2010

Posted by 흥배

1. 비관리 클래스에서 관리 클래스를 멤버로

 

비관리 클래스에서 관리 클래스를 멤버로 가지고 싶을 때는 ‘gcroot’라는 템플릿을 사용합니다.

 

#include "stdafx.h"

#include <iostream>

#include <vcclr.h>

 

using namespace System;

 

class TEST

{

public:

   TEST() {}

   ~TEST() {}

 

   gcroot< String^ > m_str;

};

 

int main(array<System::String ^> ^args)

{

    TEST test;

    test.m_str = gcnew String("Hello VSTS 2010");

 

    Console::WriteLine( test.m_str);

   

    getchar();

    return 0;

}

 



‘gcroot’를 사용하기 위해서는

#include <vcclr.h>

를 포함해야 합니다.

 

비관리 클래스에서 관리 클래스인 String을 다음과 같이 멤버로 선언합니다.

gcroot< String^ > m_str;


그리고 사용하기 위해서는 할당을 합니다.

test.m_str = gcnew String("Hello VSTS 2010");

 

 



2. 관리 클래스에서 비관리 클래스를 멤버로

 

관리 클래스에서 비관리 클래스를 멤버로 가질 때는 비관리 클래스를 포인터로 선언하여 비관리 힙에 동적할당을 합니다.

 

#include "stdafx.h"

#include <iostream>

#include <vcclr.h>

 

using namespace System;

 

class TEST

{

public:

       TEST() {}

       ~TEST() {}

};

 

ref class refTEST

{

public:

       refTEST() {}

       ~refTEST() {}

 

       TEST* test;

};

 

int main()

{

       refTEST^ refTest = gcnew refTEST();

       refTest->test = new TEST;

 

       return 0;

}

 

 

 

참고

http://msdn.microsoft.com/ko-kr/library/481fa11f%28v=VS.80%29.aspx

http://blog.naver.com/scor7910/40048083284

 


 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

Posted by 흥배

3) String^ C/C++ 문자열로 변환

 

1)번에서는 C/C++의 문자열을 String^로 변환하는 방법에 대해서 설명했습니다.

이번에는 String^ char* wchr_t*로 변환하는 방법에 대해서 설명합니다.

 

아래의 예제 코드를 봐 주세요

 

#include <string>

#include <msclr\marshal_cppstd.h>

 

using namespace System;

using namespace msclr::interop;

 

int main()

{

           System::String^ s0 = L"비주얼스튜디오2010 팀블로그";

          

           // 방법 1

           std::string tmp = marshal_as<std::string>(s0);

           const char* s1 = tmp.c_str();

           std::cout << "String^ -> string : " << s1 << std::endl;

 

           // 방법 2

           const char* s2;

           const wchar_t* s3;

           {

                     marshal_context ctx;

                     s2 = ctx.marshal_as<const char*>(s0);

                     s3 = ctx.marshal_as<const wchar_t*>(s0);

            

                     std::cout << "String^ -> char* : " << s2 << std::endl;

                    

                     setlocale(LC_ALL, "");

                     std::wcout << "String^ -> wchar_t : " << s3 << std::endl;

           }

 

           getchar();

           return 0;

}

 

String^ char* wchr_t*로 변환하는 방법은 두 가지가 있습니다.

 


첫 번째 std::string 사용


가장 간단한 방법입니다만 불필요한 std::string을 사용해야 단점이 있습니다.

std::string tmp = marshal_as<std::string>(s0);

const char* s1 = tmp.c_str();

std::cout << "String^ -> string : " << s1 << std::endl;

 

 

두 번째 marshal_context 사용


첫 번째 방법에서 std::string을 사용한 이유는 다름이 아니고 메모리 확보 때문입니다.

마샬링을 통해서 char* wchar_t*에 메모리 주소를 저장합니다. 문자열 그 자체를 복사하는 것이 아닙니다. 그래서 변환한 문자열을 저장할 메모리 주소를 확보하고 사용 후에는 해제를 해야 합니다. 메모리 확보와 해제를 위해서 marshal_context를 사용합니다.

marshal_context는 변환에 필요한 메모리를 확보하고, 스코프를 벗어날 때 메모리를 해제합니다.

const char* s2;

const wchar_t* s3;

{

           marshal_context ctx;

           s2 = ctx.marshal_as<const char*>(s0);

           s3 = ctx.marshal_as<const wchar_t*>(s0);

}

 

String^ C/C++ 문자열로 변환할 때는 std::string + marshal_as marshal_context 둘 중 하나를 선택하여 사용합니다.

 




참고

http://msdn.microsoft.com/en-us/library/bb384865.aspx

http://msdn.microsoft.com/ko-kr/library/bb531313%28VS.90%29.aspx

http://codezine.jp/article/detail/4774

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

Posted by 흥배

관리코드와 비관리코드를 혼합해서 사용할 때 서로간에 문자열을 주고 받아야 하는 경우가 종종 있을 것입니다. 관리코드와 비관리코드간에 문자열을 서로 어떻게 변환하여 주고 받는지 알아보겠습니다.

 

 

1) C/C++ 문자열을 String^으로 변환

 

먼저 아래의 변환 예제 코드를 봐 주세요

 

#include <msclr\marshal.h>

 

using namespace System;

using namespace msclr::interop;

 

int main()

{

           const char* message = "Forever Visual C++";

           String^ result1 = marshal_as<String^>( message );

           Console::WriteLine("char -> System::String : {0}", result1);

 

           const wchar_t* Wmessage = L"Visual C++이여 영원하라";

           String^ result2 = marshal_as<String^>( Wmessage );

           Console::WriteLine("wchar -> System::String : {0}", result2);

 

           getchar();

           return 0;

}

 


관리코드와 비관리코드 간의 문자열 변환에는 msrshal_as를 사용하여 마샬링합니다.

C/C++ 문자열을 마샬링하기 위해서는

#include <msclr\marshal.h>

파일을 포함하고,


using namespace msclr::interop;

네임스패이스를 선언합니다.

 

사용 방법은 아주 간단합니다.

marshal_as< 변환할 문자 타입 >( 원본 문자열 );

 


ANSI 문자열을 관리코드의 문자열로 변환할 때는 아래와 같이 합니다.

const char* message = "Forever Visual C++";

String^ result1 = marshal_as<String^>( message );

 

유니코드를 관리코드의 문자열로 변환할 때는 아래와 같이 합니다.

const wchar_t* Wmessage = L"Visual C++이여 영원하라";

String^ result2 = marshal_as<String^>( Wmessage );

 

 



2) STL string String^간의 변환

 

이것도 marshal_as를 사용합니다.

아래의 예제 코드를 봐 주세요

 

#include <iostream>

#include <string>

#include <msclr\marshal_cppstd.h>

 

using namespace System;

using namespace msclr::interop;

 

int main()

{

           std::string s0 = "비주얼스튜디오2010 팀블로그";

           std::cout << "string : " << s0 << std::endl;

 

           System::String^ s1 = marshal_as< System::String^ >(s0);

           Console::WriteLine("std::sting->System::String : {0}", s1);

 

           std::wstring s2 = marshal_as< std::wstring >(s1);

           setlocale(LC_ALL, "");

           std::wcout << "System::String->std::wstring : " << s2 << std::endl;

          

           getchar();

           return 0;

}

 

STL의 문자열과 변환하기 위해서는 다음의 헤더 파일을 포함해야 합니다.

#include <msclr\marshal_cppstd.h>

 

마샬링하는 방법은 앞에 설명한 C/C++ 문자열 변환과 같습니다.

System::String^ s1 = marshal_as< System::String^ >(s0);

 

주제와 좀 관계 없는 것으로 콘솔창에 유니코드 문자열을 출력하는 방법은 아래와 같습니다.

setlocale(LC_ALL, "");

std::wcout << "System::String->std::wstring : " << s2 << std::endl;

 setlocale로 국가를 설정하고(직접 나라를 지정할 수도 있고, 아니면 위처럼 시스템 설정에 따라가도록 할 수도 있습니다), ‘cout’ 대신 ‘wcout’를 사용합니다.

 

 



관리코드 문자열과 비관리코드 문자열간의 변환에 따른 성능


C++로 만드는 프로그램은 보통 고성능을 원하는 프로그램이므로 보통 C++ 프로그래머는 성능에 민감합니다. 마샬링은 공짜가 아닙니다만 많은 양을 아주 빈번하게 마샬링 하는 것이 아니면 성능에 너무 신경 쓰지 않아도 됩니다. 다만 기본적으로 관리코드의 문자열은 유니코드입니다. 그래서 비관리코드의 문자열이 ANSI 코드라면 유니코드를 사용했을 때 보다 더 많은 시간이 걸립니다(정확한 수치는 잘 모르지만 ANSI가 유니코드보다 3배정도 더 걸린다고도 합니다). 그래서 관리코드와 비관리코드를 같이 사용할 때는 가능한 유니코드를 사용하는 것이 훨씬 좋습니다.

 

 

아직 설명할 것이 많이 남아 있습니다. 다음을 기다려주세요^^

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

Posted by 흥배

아마 C++ 프로그래머가 C++/CLI를 사용할 때 가장 신경 쓰이는 부분이 관리 코드를 어떻게 하면 비관리 코드와 연동하는 방법이라고 생각합니다.

 

그래서 아직 C++/CLI의 델리게이트 등 C++/CLI의 특징을 설명하지 않은 것이 많지만 이런 것은 C#를 공부하면 배울 수 있는 것이므로 급하지 않다고 생각합니다. 그래서 관리 코드와 비 관리 코드의 연동에 대해서 앞으로 몇 차례에 걸쳐서 설명하려고 합니다.

 

이번은 첫 번째로 간단하게 array로 만든 배열을 비관리 코드의 포인터로 어떻게 전달하는지 설명하겠습니다.

 

먼저 코드를 봐 주세요^^

#include <Iostream>

 

using namespace System;

 

void DumpNativeArray( int* pArrNums, int length )

{

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

    {

        std::cout << pArrNums[i] << std::endl;

    }

}

 

int main()

{

array< int >^ ArrNums = gcnew array<int>(3);

ArrNums[0] = 1;

ArrNums[1] = 2;

ArrNums[2] = 3;

 

     pin_ptr<int> pNative = &ArrNums[0];

     DumpNativeArray(pNative,ArrNums->Length);

     pNative = nullptr;

 

getchar();

     return 0;

}

 

위 코드의 핵심은

pin_ptr<int> pNative = &ArrNums[0];

입니다.

 

앞서 설명한 pin_ptr을 사용하였습니다. pin_ptr을 사용하여 관리 힙에 할당된 객체가 이동하지 못하도록 고정합니다. 고정하는 이유는 비관리 코드로 메모리 주소를 넘기기 때문에 관리 힙에서 이동이 되면 안되기 때문입니다.


또 여기서 자세히 봐야 되는 것이 있습니다.

pin_ptr<int> pNative = &ArrNums[0];


pNative&ArrNums이 아닌 &ArrNums[0]을 대입하였습니다. 이유는 관리 코드에서는 &ArrNums ArrNums의 요소가 아닌 ArrNums 오브젝트 자체를 가리키는 것이기 때문입니다.

&ArrNums[0]을 대입해야 ArrNums에 들어가 있는 요소의 첫 번째 주소를 비관리 코드에 주소를 넘길 수 있습니다.

 



제가 요즘 바빠서 이번은 아주 간단하게 이것으로 끝내겠습니다.^^;

다음에는 문자열 변환에 대해서 설명하겠습니다.

 

 

참조

http://mag.autumn.org/Content.modf?id=20050507224044

 

 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

Posted by 흥배

nullptr

 

C/C++에서 포인터를 초기화 할 때 ‘NULL’을 사용합니다. 그러나 VC++ 10에는 C++0x에서는 포인터를 초기화 할 때 NULL 대신 새로 생긴 ‘nullptr’을 사용할 수 있게 되었습니다.


C++/CLI는 이전부터 nullptr이 있었습니다.

C++/CLI에서는 ref 클래스의 핸들을 초기화 할 때는 nullptr을 사용합니다.

C++/CLI, C++0x nullptr C/C++ 처럼 ‘0’이 아니라는 것을 잘 기억하시기 바랍니다.

 

 

 

interior_ptr

 

interior_ptr은 관리 힙(managed heap. GC겠죠) 상의 value type나 기본형을 가리키는 포인터라고 할 수 있습니다. interior_ptrvalue type나 기본형을 비관리 코드의 포인터처럼 사용하고 싶을 때 사용하면 좋습니다.

 

< 코드 1. >

ref class REFClass

{

public:

    int nValue;

};

 

void SetValue( int* nValue )

{

    *nValue = 100;

}

 

 

int main()

{

    REFClass^ refClass = gcnew REFClass;

    SetValue( &refClass->nValue );  // 에러

}

 

위 코드를 빌드 해 보면 SetValue( &refClass->nValue ); 에서 빌드 에러가 발생합니다. 매니지드 힙에 있는 것은 그 위치가 변하므로 비 관리 코드의 포인터를 넘길 수가 없습니다. 그럼 <코드 1>를 정상적으로 빌드 하기 위해서 interior_ptr를 사용해 보겠습니다.

 

< 코드 2. >

ref class REFClass

{

public:

    int nValue;

};

 

void SetValue( interior_ptr<int> nValue )

{

    *nValue = 100;

}

 

 

int main()

{

    REFClass^ refClass = gcnew REFClass;

    SetValue( &refClass->nValue );

}

 


<코드 2> SetValue의 파라미터로 비관리 코드의 참조나 포인터를 넘길 수도 있습니다.

< 코드 3. >

#include <iostream>

 

 

void SetValue( interior_ptr<int> nValue )

{

    *nValue = 100;

}

 

int main()

{

           int nValue = 50;

           SetValue( &nValue );

 

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

 

           getchar();

           return 0;

}

 

그리고 interior_ptr에 대신 C++/CLI의 참조(‘%’)를 사용하는 방법도 있습니다.

 

 

 

 

pin_ptr

 

pin_ptr은 관리 힙 상의 value type나 기본형을 비관리 코드에서 포인터로 사용하고 싶을 때 사용하는 기능입니다. 가장 필요한 경우가 C++/CLI에서 기존의 비관리 코드로 만들어 놓은 라이브러리를 사용할 때입니다.

 

< 코드 4. >

ref class REFClass

{

public:

    int nValue;

};

 

void SetValue( int* pValue )

{

    *pValue = 100;

}

 

 

int main()

{

    REFClass^ refClass = gcnew REFClass;

pin_ptr<int> pValue = &refClass->nValue;

    SetValue( pValue );

pValue = nullptr;

}

 

pin_ptr에 메모리 주소를 할당하는 것을 ‘pin’이라고 부르고 사용이 끝난 후 nullptr로 초기화 하는 것을 ‘unpin’ 이라고 부릅니다. pin_ptr 사용이 끝난 후 가능한 빨리 unpin 해주는 것이 좋습니다.

 

 

 

 

interior_ptr pin_ptr의 차이점

 

interipor_ptr pin_ptr은 둘 다 관리 힙 상의 value type이나 기본형을 가리키는 포인터로 사용되지만 interior_ptr은 관리 힙 상에서 인스턴스가 이동하여도 올바르게 추적할 수 있는 포인터로 런타임의 지배하에 있습니다(즉 인스턴스가 관리 힙 상에서 이동하여도 괜찮습니다).


pint_ptr은 관리 힙 상의 value type을 비관리 코드에서 사용하고 싶을 때 사용합니다. 당연히 이 때는 관리 힙에 있는 인스턴스가 이동하면 안되므로 인스턴스의 이동을 금지합니다.

 

interipor_ptr pin_ptr의 같은 점 : 포인터처럼 사용할 수 있다.

interipor_ptr pin_ptr 다른 점 : interipor_ptr은 관리 코드 상에서 포인터로 사용하고, pin_ptr는 비관리 코드에 포인터로 넘길 때 사용합니다.

 

 

interipor_ptr pin_ptr을 공부했으니 다음에는 C++/CLI에서 비관리 C++과 혼합해서 사용할 때 어떻게 해야 하는지 설명하겠습니다.

 

 

 

 

참고

http://cppcli.shacknet.nu/cli:interior_ptr

http://cppcli.shacknet.nu/cli:pin_ptr

http://cppcli.shacknet.nu/cli:interior_ptr%E3%81%A8pin_ptr%E3%81%AE%E9%81%95%E3%81%84

 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

Posted by 흥배

프로그래밍 할 때 가장 자주 사용하는 자료구조가 바로 배열입니다. 배열을 사용하지 않고 프로그래밍 하기는 힘들죠^^.

그래서 이번에는 C++/CLI에서의 배열에 대해서 이야기하려고 합니다.

 

 

C++/CLI에서의 배열은 ‘array’

 

비관리 C++에서는 배열은 ‘[]’을 사용합니다.

int Nums[10];

char szName[20] = {0,};

 

그러나 C++/CLI에서의 배열은 ‘array’라는 클래스를 사용합니다.

 

int 형의 3개의 요소를 가지는 배열은 아래와 같이 정의합니다.

array< int >^ A1 = gcnew array< int >(3);

array< int >^ A2 = gcnew array< int >(4) { 1, 2, 3 };

array< int >^ A3 = gcnew array< int >{ 1, 2, 3 };

 

다음은 간단한 사용 예입니다.

< 코드 1. >

int main()

{

           array< int >^ Numbers = gcnew array< int >(5);

                    

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

           {

                     Numbers[ i ] = i;

 

                     System::Console::WriteLine( Numbers[i] );

           }

 

           getchar();

           return 0;

}

 

 

 

array에 유저 정의형 사용하기

 

array에는 기본형(int, float )만이 아닌 유저 정의형도 사용할 수 있습니다. 다만 비관리 클래스는 안됩니다. 오직 관리 클래스(ref class)만 가능합니다. 또 그냥 ref 클래스를 그대로 넣을 수는 없는 클래스의 핸들을 사용해야 합니다(ref 클래스는 GC에 동적 할당을 하기 때문이겠죠).

 

ref class refTest

{

};

 

array< refTest >^ arrTest;    // 에러

array< refTest^ >^ arrTest;   // OK

 

 

 

 

for each 사용하기

 

앞서 <코드1>의 예제에서는 배열의 모든 요소를 순환하기 하기 위해 ‘for’문을 사용했습니다. 그러나 .NET에서는 for문 보다 ‘for each’문을 사용하는 것이 성능이나 안정성 등에서 더 좋습니다(다만 for each를 사용하면 내부에서 값을 변경할 수 없다는 문제는 있습니다).

 

< 코드 2. >

#include <iostream>

 

 

int main()

{

           array< int >^ Numbers = gcnew array< int > { 10, 11, 12, 13, 14 };

                    

           for each( int nValue in Numbers )

           {

                     System::Console::WriteLine( nValue );

           }

 

           getchar();

           return 0;

}

 

 

 

다 차원 배열

 

array는 너무 당연하게 다 차원 배열도 만들 수 있습니다.

 

< 코드 3. 2차원 배열의 예 >

int main()

{

           array<int,2>^ a2 = gcnew array<int,2>(4,4);

           array<int,2>^ b2 = gcnew array<int,2>{ {1,2,3,4},{1,2,3,4},{1,2,3,4},{1,2,3,4} };

 

           getchar();

           return 0;

}

 


 

 


array의 기능은 .NET 라이브러리의 array 클래스를 사용하므로 자세한 사용방법은 MSDN에서 .NET 라이브러리 부분을 참고 하시가 바랍니다.

 

 

다음에는 nullptr, interior_ptr, pin_ptr 설명과 관리코드의 타입을 비관리 코드로 넘길 때 어떤 작업을 하는지 이야기 하겠습니다.^^

 

 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

Posted by 흥배

 

gcnew로 생성하지 않기

 

C++/CLI는 클래스를 생성할 때 ‘gcnew’를 사용하지 않고 생성할 수도 있습니다.

 

< 리스트 1. ‘gcnew’를 사용하지 않고 클래스 생성하기 >

#include "stdafx.h"

#include <stdio.h>

 

using namespace System;

 

ref class ManagedTest

{

public:

           ManagedTest() { Console::WriteLine(L"New ManagedTest"); }

           ~ManagedTest() { Console::WriteLine(L"delete ManagedTest"); }

          

           void func() { Console::WriteLine(L"Call func() - {0}", nNumber ); }

 

           int nNumber;

};

 

void foo1()

{

           ManagedTest MTest;

           MTest.nNumber = 1;

           MTest.func();

}

 

void foo2()

{

           ManagedTest^ MTest = gcnew ManagedTest();

           MTest->nNumber = 2;

           MTest->func();

}

 

int main(array<System::String ^> ^args)

{

           foo1();

           foo2();

          

           getchar();

           return 0;

}


< 결과 >


<리스트 1> ManagedTest MTest; 는 비 관리 C++처럼 GC가 아닌 스택 영역에 생성하는 것으로 착각할 수도 있겠지만 전혀 아닙니다. 클래스를 생성하면 언제나 GC 영역에 만들어집니다.

위의 코드는 그냥 ‘gcnew’ 사용을 우리가 생략하고 컴파일러가 대신 써 준다고 생각하시면 됩니다.

 

void foo1()

{

           ManagedTest MTest;

           MTest.nNumber = 1;

           MTest.func();

}

은 컴파일러에 의해서 아래의 코드로 바뀝니다.

void foo1()

{

           ManagedTest^ MTest = gcnew ManagedTest();

           MTest->nNumber = 1;

           MTest->func();

           delete MTest;

}

 

위의 코드를 보시면 아시듯이 gcnew를 사용하지 않고 클래스를 생성하면 우리가 직접 delete를 쓰지 않아도 되는 편리함을 얻을 수 있습니다.

gcnew를 사용하지 않는 것은 C#에서 ‘using’을 간략화 시킨 것으로 생각하면 좋습니다.


< C# using 문 사용 예 >

using (Graphics g = this.CreateGraphics())

{

    g.DrawLine(Pens.Black, new Point(0,0), new Point(3,5));

}

 

 

 

 

value 클래스

 

관리 클래스는 복사 생성자와 대입 연사자를 가지지 못하므로 아래의 코드는 컴파일 에러가 발생합니다.

 

< 리스트 2. >

#include "stdafx.h"

#include <stdio.h>

 

using namespace System;

 

ref class C {

    int i;

};


void func(C c) {}


int main()

{

    C c;

    C d;

    func(c);   // 에러

    d = c;     // 에러

}

 

그러나 클래스를  ‘ref’가 아닌 ‘value’ 클래스로 정의하면 위의 코드는 컴파일 할 수 있습니다.

 

#include "stdafx.h"

#include <stdio.h>

 

using namespace System;

 

value class C {

    int i;

};

void func(C c) {}

int main()

{

    C c;

    C d;

    func(c);   // 에러

    d = c;     // 에러

}

 

value 클래스는 클래스간 복사를 할 수 있는 능력이 있습니다. 이 복사는 비트 단위의 복사로 이른바 ‘memcpy’와 같은 복사입니다.

value 클래스는 복사를 할 수 있으므로 value 클래스의 멤버는 절대 복사 가능한 멤버만 가질 수 있습니다. 그래서 아래와 같은 value 클래스 C는 컴파일 에러가 발생합니다.

 

ref class A

{

  int i;

};

 

value class C

{

  A a;

};

 

 

value 클래스의 특징으로는 ref 클래스가 GC에서 만들어지는 것과 달리 스택에 만들 수 있습니다.

value class C

{

};

 

C c;

 

위 코드에서 C 클래스는 스택에 만들어집니다(물론 gcnew를 사용하면 GC에 만들어집니다)

 

value 클래스의 특징은 좀 더 있는데 위에 설명한 것들과 포함해서 아래와 같이 정리할 수 있습니다.

 


value 클래스의 특징

 

1. 기본 생성자를 가질 수 없다.

2. 복사 생성자를 가질 수 없다.

3. 대입 연산자를 가질 수 없다.

4. 소멸자를 가질 수 없다.

5. finalize를 가질 수 없다.

6. 클래스간 복사를 할 수 있다.

7. 복사 불가능한 것을 멤버로 가질 수 없다(ref 클래스 등).

8. 스택에 생성할 수 있다.

9. 다른 클래스를 계승할 수 없다( interface는 가능하다)

 

 

 


관리 클래스를 파라메터로 넘기기

 

ref class A

{

           int i;

};

 

void foo1( A a )

{

}

 

함수 foo1의 파라미터 정의는 클래스 A value 클래스일 때만 사용할 수 있습니다. 그러므로 아래와 같이 foo1의 파라미터를 정의해야 합니다.

void foo1( A^ a )

{

}

 

 

 

 

그 외….

 

C++/CLI에서 참조는 ‘%’을 사용합니다. 이것은 비 관리의 ‘&’와 구별이 됩니다.

%는 아래와 같은 경우에 유용하게 사용할 수 있습니다.

void foo( A^ a )

{

}

 

A a;

// foo( a );  // 에러

foo( %a ); // 성공


참조는 C#에서는 'ref', VB.NET에서는 'ByRef'와 같다고 생각하시면 됩니다.


// 값을 참조로 넘기는 경우

void valuebyref(int%i)
{
   i=5;
}

// 참조형을 참조로 넘기기
void refbyref(String^%s)
{
   s="newstring";
}

void main()
{
   int i=1;

   valuebyref(i);

   String^s="basestring";
   refbyref(s);
}
( 위 코드는 http://adversaria-june.blogspot.com/2006/08/ccli_26.html 에서 인용했습니다 )

 



구조체는 관리나 비 관리나 다른 점은 없습니다.


 

참조와 구조체는 너무 짧게 끝나버렸네요^^;

 

 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

Posted by 흥배

C C++의 큰 차이점의 하나가 바로 C++에만 있는 클래스입니다. 또 클래스는 객체 지향 프로그래밍 언어에서 자주 볼 수 있습니다.

 

C++/CLI에서 관리 클래스는 ‘ref’라는 키워드를 사용하여 만듭니다.

 

비 관리 클래스

class Test

{

};

 

관리 클래스

ref class Test

{

};

 

관리 클래스는 ‘ref’를 제외하고는 외관상으로는 비 관리 클래스와 비슷하지만 관리와 비 관리가 많이 다르듯이 관리 클래스는 비 관리 클래스와 다른점이 있습니다. 그러므로 이것을 잘 파악하고 있어야 합니다.

 

 

 

관리 클래스의 특징

 

1. 정적 할당은 안 된다. 무조건 가비지컬렉션(GC)에 동적으로 생성한다.

 

2. 복사 생성자를 만들 수 없다.

 

3. ‘^’(핸들이라고 부른다)‘gcnew’를 사용하여 클래스를 생성한다. 당근 메모리 해제는 GC에서 관리한다.

 

4. 핸들은 네이티브의 ‘*’(포인터) ‘&’(참조)와 비슷한 것으로 더 안정스럽다.

 

5. ‘delete’는 명시적으로 클래스에서 사용하고 있는 리소스를 해제할 때 사용하는 것으로 소멸자가 호출 되는 것이지 메모리에서 해제하는 것은 아니다. delete GC에 있는 메모리를 해제하는 것은 아니다.

 

6. delete로 소멸자를 호출하면 GC에 의해서 진짜 파괴될 때 소멸자는 호출되지 않는다.

(소멸자를 선언한 클래스는 자동적으로 IDisposable 인터페이스를 구현한다. 소멸자는 컴파일러에 의해서 Dispose() 메소드로 치환된다).

 

7. 소멸자 이외에 'finalize'를 선언할 수 있다. finalize GC에서 인스턴스가 파괴될 때 호출된다. delete로 소멸자를 호출한 경우에는 finalize는 호출되지 않는다.

 

8. finalize‘!’ 키워드를 사용한다.

 

 

 

관리 클래스 사용해 보기

 

< 코드 1. 관리 클래스 정의 및 사용 >

#include "stdafx.h"

 

using namespace System;

 

ref class ManagedTest

{

public:

           ManagedTest() { Console::WriteLine(L"New ManagedTest"); }

           ~ManagedTest() { Console::WriteLine(L"delete ManagedTest"); }

           !ManagedTest() { Console::WriteLine(L"finalize ManagedTest"); }

};

 

int main(array<System::String ^> ^args)

{

           Console::WriteLine(L"1.");

          ManagedTest^ MTest1 = gcnew ManagedTest();

           delete MTest1;

 

           Console::WriteLine(L"2.");

           ManagedTest^ MTest2 = gcnew ManagedTest();

          

           return 0;

}

 

< 결과 >





<코드 1> 설명



< 그림 1. <코드 1>의 소스 코드와 결과 >

 

<그림 1> 코드를 보면 3번의 ‘gcnew’, 4번의 ‘^’를 사용하여 ManagedTest를 생성하였습니다.

<코드 1>에는 없지만 핸들은 포인터와 같은 것으로 관리 클래스의 멤버를 사용할 때는 ‘->’를 사용합니다.

5 delete를 사용하면 소멸자가 호출되어서 6번이 출력됩니다.

MTest2는 소멸자를 호출하지 않아서 8번에서 정의한 finalize가 프로그램이 종료할 때 호출됩니다(7).


 

<코드 1>은 아주 짧고 단순한 코드이지만 관리 클래스의 대부분의 특징을 다 나타내고 있습니다. 관리 클래스에 대한 설명은 아직 남아 있습니다. 이것은 다음 회에 또 설명하겠습니다.



저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

Posted by 흥배

앞서 두 번을 걸쳐서 C++/CLI에 대해서 잘 모르는 분과 싫어하는 분을 위해서 제 생각이나 MSDN에 있는 글을 정리해서 포스팅 했습니다.

 

이제 본격적으로 C++/CLI에 대해서 설명해 나가겠습니다(이 글을 보는 분들은 C++을 알고 있다고 가정을 하겠습니다).

 

 

 

1. ‘C++/CLI가 뭐야?’

 

라고 질문을 하면 가장 초 간단한 답은 ‘.NET에서 C++를 사용하기 위한 언어라고 말할 수 있습니다. 그런데 이 답은 너무 간단하고 없어 보이죠? ^^;

그래서 좀 유식하게 보일 수 있도록 고급스럽게 답해 보겠습니다(또는 복잡하게).

 

C++/CLI에서 CLI‘Common Language Infrastructure’의 약자입니다.

 

C++/CLI CLI 환경에서 돌아가는 프로그램을 만들기 위한 언어입니다. C++/CLI는 마이크로소프트(이하 MS)가 만들었지만 공업 표준화 단체인 ECMA에 의해서 표준 언어로 제정 되어 있습니다.

 C++/CLI MS가 만들었기 때문에 현재까지는 실행 환경이 Windows .NET 플랫폼이지만 언어 사양 상으로는 Windows .NET 플랫폼에만 사용할 수 있는 것이 아닙니다. 이론적으로는 Windows 이외의 Unix Linux, Mac에서도 실행할 수 있습니다(누구라도 Windows 이외서도 사용할 수 있도록 언어 사양을 따라서 구현만 하면 됩니다).

 

C++/CLI C++로 만든 프로그램을 거의 그대로 컴파일 할 수 있습니다.

C++의 표준 기능에 CLI를 위한 추가 기능이 더해져 있습니다.

 

 

 

2. 가장 많은 프로그래밍 언어로 만드는 프로그램 만들기

 

가장 많은 프로그래밍언어로 만드는 프로그램은 무엇일까요? 제가 생각하기에는 그 유명한 ‘Hello World’라고 생각합니다. 제가 공부한 대부분의 프로그래밍 언어 책에는 첫 번째 예제 프로그램이 Hello World였습니다.

 

그래서 C++/CLI도 관례(?)에 맞추어서 ‘Hello World’ 프로그램을 만들어 보겠습니다.

(VS의 마법사 기능에 의해서 코딩을 하나도 하지 않고 프로그램이 만들어집니다.)


< 그림 1. CLR 콘솔 어플리케이션을 선택합니다 >


< 리스트 1. ‘Hello World’ >

#include "stdafx.h"

 

using namespace System;

 

int main(array<System::String ^> ^args)

{

    Console::WriteLine(L"Hello World");

    return 0;

}

 

<리스트 1>의 코드는 <그림 1>에서 ‘OK’ 버튼을 누른 후 자동으로 생성되는 코드입니다. 이것을 빌드 후 실행을 하며 아래와 같은 결과가 나옵니다.



 

그런데 문제는 실행과 동시에 종료되어서 결과를 볼 틈이 없습니다.

예전에 C++에서는 이런 경우 코드의 아래에 ‘getchar()’를 사용하여 결과를 보고 종료시켰습니다.

그런데 다들 아시겠지만 ‘getchar()’라는 함수는 .NET 라이브러리에 있는 함수가 아닌 네이티브의 함수입니다. C#이라면 바로 사용하지 못하겠지만 C++/CLI는 이런 네이티브의 함수를 바로 사용할 수 있습니다.

 

<리스트 2. getchar() 사용 >

#include "stdafx.h"

#include <stdio.h>

 

using namespace System;

 

int main(array<System::String ^> ^args)

{

    Console::WriteLine(L"Hello World");

                 

getchar();

    return 0;

}

 

<리스트 2>.NET 라이브러리와 네이티브가 자연스럽게 공존하고 있습니다.

이런 것이 C++/CLI이기 때문에 가능한 것입니다.

 

C++/CLI로 만들어진  'Hello World' 소스 코드를 보면 C++ 프로그래머라면 몇개 처음보는 것이 있지만 이름만 봐도 대충 어떤 의미를 가지고 있는지 쉽게 파악할 수 있어서 소소 코드가 전혀 어렵지 않을 것입니다.

C++/CLI는 기존의 C++에서 CLI가 더해진 것으로 간단하게 말하면 이 더해진 'CLI'만 공부하면 C++/CLI는 마스터합니다.



앞으로 더해진 'CLI' 부분에 대해서 설명해 나가겠습니다.

다음에는 C++의 트레이드마크인 클래스 C에서부터 친숙한 struct C++/CLI에서는 어떤 의미를 갖고 어떻게 사용되는지 알아 보겠습니다.

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

Posted by 흥배

C++/CLI에 대한 기술 아티클이 별로 없는 편입니다. 좀 오래 되었지만 MSDN 매거진 2005 1월에 연재된 'Visual C++ 의 프로그래밍 모델과 컴파일러 최적화를 사용한 어플리케이션의 강화'( http://msdn.microsoft.com/ko-kr/magazine/cc163855%28en-us%29.aspx )라는 글을 통해서 간단하게 정리해 보겠습니다.

이 글을 통해서 C++/CLI의 특징이나 .NET 언어 중에서 어떤 특징을 가지고 있는지 알 수 있습니다.

 

 

 

유연한 프로그래밍 모델

 

C++ C#에 비해 언어적 표현력이나 라이브러리가 부족하다는 단점이 있지만 C#에 비해서 프로그래머가 가질 수 있는 자유도가 무척 높습니다(때로는 이것 때문에 많은 문제를 일으키지만).

C#으로 프로그래밍을 할 때는 무조건 객체 지향 프로그래밍 모델만 사용해야 합니다. 그러나 C++는 절차형 프로그래밍, 객체 지향 프로그래밍, 제너릭 프로그래밍, 메타 프로그래밍 등 프로그래머가 원하는 모델을 선택하여 프로그래밍 할 수 있습니다.

.NET에서 C++/CLI를 사용하면 이런 C++의 장점을 바로 얻을 수 있습니다.

 

 

 

어떤 .NET 언어보다도 뛰어난 성능

 

보통 .NET에서 프로그래밍 할 때 어떤 언어를 사용하나 동일한 성능을 낸다고 생각하지만(즉 언어는 달라도 컴파일 결과로 나오는 MSIL은 동일하다고) 이것은 잘 못된 생각입니다.

C++ 컴파일러 팀은 수년에 걸쳐 네이티브 코드의 최적화로부터 얻었던 지식을 C++/CLI의 최적화에 적용할 수 있도록 많은 노력을 했습니다. 그 결과 다른 .NET 언어보다 최적화된 MSIL를 만들어냅니다.

 

VC++은 어느 컴파일러보다 최상의 최적화를 제공하고 이것은 네이티브 뿐만이 아닌 매니지드 코드에 대해서도 같습니다. VC++ 컴파일러는 네이티브 코드의 모든 최적화 방법을 MSIL에도 적용하여 다른 .NET 언어보다 더 뛰어난 최적화를 할 수 있습니다.

 

.NET에서 가장 최적화된 .NET 코드를 만들어 내는 것은 C++/CLI 입니다.

 

 

 

네이티브 코드와 상호 운용 가능

 

사실 C++/CLI .NET에서 가장 큰 의미를 갖는 것이 바로 이 부분이라고 생각합니다.

.NET의 다른 언어에서 네이티브 코드를 사용하려면 네이티브 코드를 DLL로 만들어서 P/Invoke로 호출해야 합니다. 그러나 C++/CLI는 네이티브 코드와 매니지드 코드를 혼합하여 사용할 수 있습니다. 네이티브 함수로부터 매니지드 함수를 호출하는 경우 특별한 구문을 기술할 필요가 없습니다.

 

네이티브에서 매니지드 호출 또는 매니지드에서 네이티브를 호출하는 경우 서로간의 경계를 넘어가야 하므로 비용이 발생하는데 이런 호출을 최대한 줄여야 성능에 좋습니다. C#의 경우에는 서로간의 호출을 줄여야 하는 경우 인터페이스 변경 등이 필요하나 C++/CLI /clr 스위치를 사용하는 것으로 쉽게 변경할 수 있습니다. 이러한 결과로 네이티브와 매니지드 간의 호출에 발생하는 비용을 최소화 할 수 잇습니다.

 

매니지드 코드와 네이티브 코드의 상호 운용에서 가장 비싼 비용은 마샬링입니다. C#의 경우 P/Invoke를 호출할 때 CLR에 의해서 암묵적으로 마샬링이 실행됩니다. 그러나 C++/CLI는 프로그래머가 필요에 따라서 명시적으로 마샬링을 할 수 있어서 한번 마샬링한 데이터를 복수로 사용할 수 있어서 마샬링에 의한 비용을 줄일 수 있습니다.

 

 

 

.NET 프로그램의 처음 실행 시의 딜레이

 

.NET으로 만든 프로그램과 네이티브로 만든 프로그램의 차이 중의 하나가 .NET으로 만든 프로그램은 처음 실행 시에 CLR을 읽기 위해 딜레이가 발생하는 것입니다. 그러나 C++/CLI는 이런 문제를 회피할 수 있습니다.

VC++에는 DLL 딜레이 로딩 이라는 기능이 있습니다. 링커 옵션에서 /DELAYLOAD:dll에 딜레이 로딩을 할 .NET 어셈블리를 지정하면 네이티브 프로그램과 동일한 정도의 속도록 실행 시킬 수 있습니다.

 

 

 

좀 더 C++/CLI가 다른 .NET 언어보다 좋은 점이 있지만 이것으로 줄이겠습니다.

C++/CLI를 아시는 분들은 언어적 위치의 애매함에 의해서 좋지 않은 인상을 가진 분들이 많으리라 생각하는데 제가 소개한 장점을 통해서 조금이나마 좋은 인상을 얻으셨는지 모르겠네요^^.

 


C++/CLI가 다른 .NET 언어보다 어떤 특징을 가지고 있는지 좀 더 자세하게 알고 싶다면 위에 소개한 MSDN 매거진의 원문(영어)을 보시던가 또는 제가 발 번역한 글을 보시기 바랍니다.

 

Visual C++ 의 프로그래밍 모델과 컴파일러 최적화를 사용한 어플리케이션의 강화

http://jacking75.cafe24.com/MSDN_MagaZine/C++Rule_200501.htm

 

그리고 아래의 글도 참고하시기 바랍니다.

C++/CLI: .NET 프레임워크 프로그래밍을 위한 가장 강력한 언어

http://anyflow.net/entry/CCLI-NET-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%84-%EC%9C%84%ED%95%9C-%EA%B0%80%EC%9E%A5-%EA%B0%95%EB%A0%A5%ED%95%9C-%EC%96%B8%EC%96%B412


http://anyflow.net/entry/CCLI-NET-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%84-%EC%9C%84%ED%95%9C-%EA%B0%80%EC%9E%A5-%EA%B0%95%EB%A0%A5%ED%95%9C-%EC%96%B8%EC%96%B422

 

 

C++/CLI 의 설계 원리와 발전 과정

http://msdn.microsoft.com/ko-kr/magazine/cc163484.aspx

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

Posted by 흥배

안녕하세요. 저는 작년에 스터디에 합류하면서 C++0x VC++ 10 Concurrency Runtime에 대해서 글을 적고 강연을 했었습니다. 아직 C++0x Concurrency Runtime에 대한 모든 것을 다 다루지 못했지만 이번에 새로운 멤버들이 합류하여 이 분들이 제가 이전에 맡았던 부분을 맡아서 할 예정이므로 저는 새로운 것을 하려고 합니다.

 

제가 하려는 것은 C++/CLI에 대한 것입니다.

사실 원래 작년부터 저는 C++/CLI을 공부하면서 정리해 보려고 했는데 작년 4월에 스터디에 합류하면서 계속 미루어졌습니다.

 

 

보통 .NET에서 프로그래밍을 한다고 하면 C#으로 프로그래밍 한다고 생각합니다. 그리고 네이티브 프로그래밍을 한다고 하면 C++입니다. 그럼 C++/CLI는 무엇일까요?

 

이름으로 유추 해 볼까요? ‘C++/CLI의 첫 단어는 ‘C++’입니다. ‘C++’ 이라고 하니 딱 네이티브 냄새가 나는군요. 두 번째 단어는 ‘CLI’입니다. C#으로 프로그래밍 하시는 분들은 ‘CLI’가 무엇을 뜻하는지 아시죠? ‘CLI’ .NET의 냄새를 풀풀 풍깁니다. ‘C++/CLI’라는 단어는 네이티브와 .NET의 냄새가 동시에 나지 않나요? 만약 그렇다고 생각하신 분들은 냄새를 잘 맡은 것입니다.^^

 

‘C++/CLI’가 네이티브와 .NET의 냄새를 동시에 풍기듯이 프로그래밍 측면에서도 ‘C++/CLI’는 네이티브와 .NET의 중간 지점에 있는 언어라고 할 수 있습니다.

 

 

 

폭 넓은 또는 이도 저도 아닌 어중간한

 

어떤 영역에서 중간 정도의 위치에 있으면 좋은 말로는 한쪽에 쏠리지 않으면서 양쪽 모든 것을 다 할 수 있다고 들을 수 있지만, 나쁜 말로는 이도 저도 아니라는 말도 들을 수 있습니다.

 

C++/CLI도 그런 것 같습니다.

 

먼저 C++/CLI의 나쁜 점은 .NET 프로그래머와 네이티브 프로그래머 양쪽 모두가 썩 마음에 들어하지 않는 언어라는 것입니다. .NET 프로그래머가 보기에는 이미 C#이라는 좋은 언어가 있어서 다른 언어는 눈에 잘 들어오지도 않고, 네이티브에는 관심이 없는 분들도 많습니다.

 

네이티브 프로그래머에게는 C++라는 걸출한 언어가 있고 일의 특성상 .NET으로는 하기 힘들어서 .NET 프로그래머가 사랑하는 C#도 들어올 공간이 없을 정도입니다. 그런데 C++/CLI를 보니 ‘C++’이라는 단어에 반가움을 가지고 봤더니 C++와 비슷한 것 같으면서 문법이 미묘하게 다른 것이 꽤 마음에 들지 않습니다(C++ 프로그래머가 보기에는 해괴하게 생겼습니다).

 

C#, C++ 어느 하나도 제대로 마스터하기 힘든데 C++/CLI를 제대로 사용하기 위해서는 .NET 프로그래머는 C++을 알아야 하고, C++ 프로그래머는 .NET을 알아야 합니다. 이 바쁜 세상에 하나도 제대로 마스터하기 힘든데 두 개나 알아야 합니다. -__-

 

혹시 여기까지 읽고 “C++/CLI 나쁜 언어군. 이런 잉여 언어라고 생각하고 창을 닫으려고 하는 건 아니겠죠? 조금만 더 기다려 보세요. 이제 좋은 말을 좀 할 테니 이것도 보세요^^

 

그럼 이제 좋은 점을 말해 보겠습니다.

.NET C++(네이티브) 둘 다 각각의 장점을 많이 가지고 있지만 완벽하지는 않습니다.

.NET 프로그래머 입장에서는 아직 세상에는 C++ C로 만들어진 라이브러리가 많고, .NET C++에 비해서 아직은 성능이 낮기 때문에 .NET만으로는 부족한 경우가 있습니다. C++ 프로그래머 입장에서는 요즘 같이 생산성을 추구하는 환경에서 .NET에 비해 낮은 생산성 때문에.NET 환경이 부럽습니다. C++/CLI는 이런.NET 프로그래머와 C++(네이티브) 프로그래머의 아쉬운 부분을 해결해 줄 수 있습니다.

 

물론 C++/CLI를 사용하지 않아도 .NET에서 네이티브 라이브러리를 사용하고, C++ 프로그래머는 .NET으로 만들어진 라이브러리를 사용할 수 있지만 규모가 작지 않은 경우라면 C++/CLI를 사용하는 것보다 까다롭습니다.

 

 

제가 일하고 있는 게임 업계에서는 주력 언어는 C++이고, 예전이나 지금 만들고 있는 대 부분의 라이브러리는 C++을 사용하여 만들고 있습니다. 그러나 게임 개발을 위한 회사에서 사용할 인하우스 툴을 만들 때는 C++만큼의 고 성능을 필요로 하지 않으면서 C++로 만든 라이브러리를 사용하고, 빠르게 개발하고 유지보수가 간편하기를 원하므로 .NET과 네이티브가 결합되기를 바랍니다. 바로 이럴 때가 ‘C++/CLI’가 적격입니다.

 

C++/CLI의 가장 큰 단점은 C# 프로그래머가 보기에도 이상하고, C++ 프로그래머가 보기에도 생김새가 이상해서 흥미를 일으키지 못한다는 점과, C++/CLI를 올바르게 알기 위해서는 .NET C++을 모두 알아야 된다는 점이라고 생각합니다.

그러나 이 단점이라는 부분이 .NET C++ 양쪽 모두를 아는 프로그래머에게는 어느 한쪽만을 아는 프로그래머에 비해 양쪽의 장점을 적절하게 다 가져갈 수 있습니다.

 

.NET이나 C++ 한쪽만을 아는 사람에게는 C++/CLI는 미운 오리새끼이지만 양쪽 모두 아는 사람에게는 백조가 될 수 있습니다.

이 블로그를 통해서 아직까지는 미운 오리새끼로 취급 받고 있는 C++/CLI를 백조가 될 수 있도록 해보겠습니다.

 

 

적다 보니 생각보다 글이 길어졌네요. 첫 글을 너무 쓸데 없이 주절댄 것은 아닌가 모르겠습니다.^^;

 

다음부터는 .NET에서의 C++/CLI의 의미에 대해서 정리하고, C++/CLI에 대한 설명, C++/CLI를 사용한 .NET과 네이티브의 결합, C++/CLI .NET Framework 4 사용 이라는 순서로 글을 올려보겠습니다.

 

 

ps : C++/CLI .NET이 처음 나올 때는 ‘Managed C++’이라는 이름으로 불렸습니다. 그러다가 VS 2005가 나오면서 C++/CLI로 이름이 바뀌었습니다. 또한 문법적인 면에서도 차이가 있습니다.

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. C++을 매니지드로 끌어 올리는 아이디어는..좋으나.. 곧 없어질 C++/CLI 라서..; 배워봐야 시간낭비라는 생각밖에 안드네요..

    C++을 매니지드 환경에서 쓴다고 해도.. .NET 문법을 다량 섞어서 사용하게 되는데. 이건 머 C#반 C++반 사용하고.. 사용법은 C++보다 어렵고..

    결국은 둘 다 쓰게 됩니다. 완전 망한 언어죠..실제 사용하는 사람들도 거의 없어서.. 아마도 VS2012에서 지원이 끊기고 2014버전 정도면 아예 없어질 기세입니다ㅡㅡ;


    // 반대로.. C#이나 F#등 을 네이티브 컴파일해서 배포를 할 수 있으면 좋았을텐데요.. 이미 캐쉬로는 되고 있다지만.. 중간언어로 배포를 하게 되면.. 이건 머 오픈소스도 아니고....
    (ngine.exe 나 배포할 떄 사용했으면 좋겠습니다.)

  2. powerdraw 2010/05/11 20:21

    얼마전 저도 회사 프로젝트에서 라이브러리를 변환할 일이 생겨 C++/CLI를 고려해본 적이 있었습니다^^
    다행히 라이브러리 규모가 크지 않아 다른 식으로 해결했습니다만...

    구현은 둘째치고 유지보수 면에서도 쉽지는 않은 부분이고
    향후에 MS에서 C++/CLI를 계속 존속시킬지도 의문이구요;;;

Posted by 흥배

영문판 VS 2010(Visual C++ 10)은 나왔고, 한글판은 61일에 나온다고 합니다.

 

Visual C++ 10을 도입하려고 하시는 분들은 전체적으로 어떤 변화가 있는지 알고 싶을 것이고, 특히 구매를 위해 회사 윗 분들에게 보고를 해야 되는 분들은 관련된 문서를 만들어야 하는 분들도 있으리라 생각합니다.

 

VC++ 10 도입이나 내부 스터디에 사용하도록 간단하게 VC++ 10의 달라진 점을 정리하여 문서를 만들어 보았습니다.

 

이 문서는 러프하게 만들어진 문서이니 참고로 사용하여 더 좋은 문서를 만드시기를 바랍니다. 특히 윗 분들에게 보고 하기 위해서 PT문서를 만들 때는 이 문서에 왜 필요한지에 대해서 좀 더 강력한 메시지를 넣기를 바랍니다.^^






저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

'Language Development > Visual C++ 10' 카테고리의 다른 글

Visual C++ 10의 변화  (0) 2010/05/02
디버깅 모드에서 역어셈블리 코드 보기  (1) 2010/02/04
About Visual C++ 10  (0) 2009/10/15

댓글을 달아 주세요

Posted by 흥배

C++0x 관련 책 "Visual C++ 10 C++0x"가 오늘 한국 MSDN 사이트에 올라왔습니다.

e-book으로 보기를 원하는 분이나 책을 얻지 못한 분들은 다운로드 해서 보세요

 

MSDN : http://msdn.microsoft.com/ko-kr/default.aspx


 


Visual Studio의 시작 페이지에도 다운로드 링크가 표시됩니다.

 

 

그리고 책에 오타가 있습니다.

48페이지 decltype 설명에서 오타가 있습니다.




팀블로그에 예전에 RValue Reference lambda 관련 글을 올린 적이 있는데 책을 만들 때 제가 올린 글을 다시 보니 설명에 미흡한 부분이 많아서 RValue Reference lambda는 새로 적었습니다. 그러니 RValue Reference lambda를 공부할 때는 꼭 블로그에 올라와 있는 글보다 이 책의 글을 보시기 바랍니다.


저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. 와 visual studio 시작페이지에 뜨는거 너무 멋있습니다 +_+)b
    글 정리하신다고 정말 수고 많으셨어요 ^^

  2. 이상영 2010/04/21 00:05

    수고 하셨습니다. 좋은 글 감사합니다.

  3. 안승근 2010/04/22 11:33

    visual studio 시작페이지에서도 뜨고 데브피아에도 누군가 링크를 걸어주셨더라고요.
    잘받아서 보았습니다. ^^

  4. 꽃집총간, 이상영, 안승근 // 고맙습니다.^^

Posted by 흥배

안부 게시판에 Gerndal님이 아래의 코드를 실행하면 메모리 leak이 난다고 알려 주셨습니다.

 

#include "stdafx.h"

#include <ppl.h>

using namespace Concurrency;

 

int main()

{

_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

 

parallel_invoke( [] { }, [] { } );

return 0;

}

 

코드를 보면 메모리 leak이 날 조건이 하나도 없습니다. 그런데 왜 메모리 leak이 날까요?

영문판 MSDN 커뮤니티에 가보면 같은 문제로 질문하고 있는 것을 찾을 수 있습니다.

 

메모리 leak이 감지되는 것은 정말 메모리 leak이 발생한 것은 아닙니다. 문제는 ConcRT의 스케줄러가 해제되기 전에 프로그램이 먼저 종료되기 때문에 발생하는 것입니다.

 

위 코드를 보면 스케줄러와 관련된 코드는 하나도 보이지 않지만 암묵적으로 사용하고 있습니다.

이 문제를 해결하기 위해서는 스케줄러를 시작 부분에서 명시적으로 정의하고 프로그램이 종료하기 전에 스케줄러를 명시적으로 해제하는 것으로 해결할 수 있습니다( 혹은 정말 메모리 leak이 아니니 그냥 무시해도 됩니다 ).

 

 

메모리 leak 경고를 발생시키지 않기 위해서는 아래와 같이 하면 됩니다.

 

int main()

{

    HANDLE hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );

    CurrentScheduler::Create( SchedulerPolicy() );

    CurrentScheduler::RegisterShutdownEvent( hEvent );

 

 

    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

 

    parallel_invoke( [] {}, [] {} );

 

 

    CurrentScheduler::Detach();

    WaitForSingleObject( hEvent, INFINITE );

    CloseHandle( hEvent );

    Sleep(500);

 

    return 0;

}

 

암묵적으로 스케줄러를 정의했다면 프로그램이 종료될 때 깔끔하게 해제되어야 하는데 이 부분이 매끄럽지 못한 것이 아쉽습니다. 현재 관련 개발자는 이번 버전에서는 깔끔하게 처리하는 부분을 미처 넣지 못했지만 꼭 다음 버전(VC++ 11)에서는 꼭 해결하겠다고 이야기 합니다.

 

 

ps : 이것은 415일 세션에서 제가 언급하였습니다만 블로그에는 포스팅을 늦게 하게 되었습니다.

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. 질문에 답변 해주셔서 감사합니다.

    VS 다음 버전이 아닌 VS2010버전에서 패치식으로 해결이 가능하면
    좋겠네요^^

  2. 음~
    알려주신데로 하면
    Leak이 났다가 나지 않았다가 그러네요

    전체에 감싸서 코드를 넣어서 그런가요?
    쓸때마다 각각을 감싸야 할까요?

    • 제 생각으로는 프로그램 초기와 마지막에 넣어주면 될거라고 생각합니다. ConcRt의 라이브러리를 사용할 때마다 해줄 필요는 없고, 해서도 안될거라고 생각합니다.

      그리고 스케줄러를 명시적으로 정의하고 해제하는 것은 ifdef 등으로 디버그모드에서 메모리릭 체크할 때만 사용하면 좋을 것 같습니다. 또 명시적으로 정의했는데 leak 경고가 나왔다 안 나왔다하면 마지막의 Sleep 값을 좀 더 크게 해보세요

  3. Sleep이 전혀 영향을 미치지 않는듯 합니다.
    지금으로써는 Leak검사를 할때의 코드와 그렇지 않을때의
    코드를 따로 작성해야 할 듯 하네요

    parallel 프로그래밍이 아주 편리해졌는데,
    이 문제때문에 좀 번거로워 졌네요~^^

Posted by 흥배

4월 15일에 열린 “C++ 개발자/게임개발자를 위한 VS2010 세미나에서 제가 이때까지 VSTS 2010 팀블로그에 올린 C++0x와 관련된 글을 작은 책으로 만든 것이 마지막에 참석하신 분들에게 배포 되었습니다.

 

원래는 pdf 파일로만 공개될 줄 알았는데 작은 분량이지만 이렇게 책으로 나왔습니다. 생각 이상으로 책 편집도 잘 되었더군요. 책 내용은 팀블로그에 올린 글을 좀 더 다듬었습니다만 RValue Reference lambda는 제가 올린 글이 좋지 못해서 새롭게 적었습니다.

 

제가 글을 아직은 잘 적는 편은 아니라서 글이 매끄럽지 못할 수도 있습니다만 좋게 봐 주시기를 바랍니다.^^;

이 책에 나온 것만 아시면 VC++ 10에 추가된 C++0x의 기능을 사용하기에는 전혀 문제가 없다고 생각합니다. 꼭 도움이 되었으면 합니다.


이번 세미나를 위해 한국에 오신 VC++ 제품의 PM인 Ulzii씨의 싸인도 받았습니다.^^

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

  1. Simple Coder 2010/04/17 09:14

    PDF 파일 좀 올려주실 수 있으신지요?

  2. 얇지만 내용이 알차서 보기도 편하네요.. 잘 보겠습니다.^^

  3. 이거 PDF파일 받을 수 있나요?

  4. decltype 소개에 decltype(HP*) pHp = &hp;

    이 문법이 오타가 났네요 ^^;

    decltype(HP) *pHp = &hp;

  5. 호환성 2010/04/18 19:10

    하나 궁금한게있습니다.
    VS 2010 에 C++ 0x가 추가되었는데 기존의 컴파일러 VS 2003 ~ 2008 에서는 C++ 0x를 사용하지 못하게 되는 건가요??
    VS 2003이후 컴파일에 문제가 없으면 2010에서도 문제가 없다고 했었는데 그 반대는 어떤지 궁금하네요.
    마이크로소프트에서 따로 업데이트를 지원해 주는건지요 :)

    • 앞으로도 2003 ~ 2008은 C++0x를 지원하지 않습니다. 다만 2008에 있는 tr1(SP1 설치 후 사용 가능)은 C++0x의 라이브러리 부분입니다.

  6. Synch3D // 고맙습니다.^^
    Simple Coder, gerndal // 아마 조만간 한국 MSDN 홈페이지에 공개될 예정으로 알고 있습니다.

  7. decltype에 오타가 있습니다. ^^;;;;

    decltype(Hp*) pHp = &Hp; 이 아니고
    decltype(Hp) *pHp = &Hp; 입니다.

Posted by 흥배

Visual C++ 팀 블로그에 C++0x Core Language Features In VC10: The Table라는 이름으로 C++0x의 기능 중 코어 언어와 관련된 것 중에서 VC++ 10에 구현된 것들을 테이블 표로 정리되어 있습니다.

GCC C++0x 구현 항목 테이블 표 형식을 차용했다고 하네요.


 

 

위의 테이블 표에서는 C++0x가 처음 구현된 VC++9VC++ 10을 비교하고 있습니다.

 

그리고 글의 마지막에 작년에 Boost Con(Boost 라이브러리 관련 행사)에서 발표한 자료가 첨부 파일로 있습니다. 이 문서를 보면 VC++ 10에서 구현한 C++0x의 코어 언어 기능들을 설명하고 있습니다.

 

문서를 보니 큰 기능들은 제가 작년부터 공부하면서 저희 팀 블로그나 여러 장소에서 설명 하였지만 일부 기능은 저도 미쳐 파악 하지 못한 것들도 있더군요. 앞으로 이런 빠진 부분에 대해서 팀 블로그를 통해서 설명해 드리겠습니다.^^


 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

Posted by 흥배

VC++ 10 C++0x나 병렬 프로그래밍 라이브러리 이외에도 툴적인 측면에서도 여러 좋은 기능들이 추가 되었습니다. 알고 있으면 작업할 때 편리한데 시간이 부족하여 제가 아직 자세하게 찾아보지 못해서 소개하지 못한 것이 많이 아쉽습니다. 그래서 짥은 것이라도 틈틈이 시간나면 소개하려고 합니다.

 

 

VC++ 10에서는 디버깅 모드에서도 역어셈블리 코드를 볼 수 있습니다.

 

메뉴에서 “Debug” -> “Windows” -> “Disassembly”를 선택합니다.



아래와 같이 역어셈블리 코드 창이 나타납니다.



그러나 위 화면을 보면 코드 바이트는 표시되지 않고 있습니다.

코드 바이트를 보고 싶다면 위 화면 왼쪽 상단의 “Viewing Option”을 클릭합니다.



위와 같이 옵션을 선택할 수 있습니다. 이 중 “Show code bytes”를 선택합니다.

그러면 아래와 같이 코드 바이트가 표시됩니다.



 

 

 

참고

http://d.hatena.ne.jp/kkamegawa/20100130/p1

 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

'Language Development > Visual C++ 10' 카테고리의 다른 글

Visual C++ 10의 변화  (0) 2010/05/02
디버깅 모드에서 역어셈블리 코드 보기  (1) 2010/02/04
About Visual C++ 10  (0) 2009/10/15

댓글을 달아 주세요

  1. 도플광어 2010/02/17 11:01

    찾던 자료인데 감사합니다^^;

Posted by 흥배

오랜만에 팀 블로그에 C++0x 관련 글을 올립니다.

이미 알고 계시겠지만 Visual Stuido 2010 Beta2에 새로운 C++0x 기능이 추가 되었습니다.

추가된 것은 nullptr 이라는 키워드 입니다.

nullptr C++0x에서 추가된 키워드로 널 포인터(Null Pointer)를 나타냅니다.

 

 

null_ptr이 필요한 이유

 

C++03까지는 널 포인터를 나타내기 위해서는 NULL 매크로나 상수 0을 사용하였습니다.

그러나 NULL 매크로나 상수 0을 사용하여 함수에 인자로 넘기는 경우 int 타입으로 추론되어 버리는 문제가 발생 합니다.

 

< List 1 >

#include <iostream>

 

using namespace std;

 

void func( int a )

{

cout << "func - int " << endl;

}

 

void func( double *p )

{

cout << "func - double * " << endl;

}

 

int main()

{

func( static_cast<double*>(0) );

                 

func( 0 );

  func( NULL );

                 

getchar();

return 0;

}

 

< 결과 >

 


첫 번째 func 호출에서는 double* 로 캐스팅을 해서 의도하는 func이 호출 되었습니다. 그러나 두 번째와 세 번째 func 호출의 경우 func( doube* p ) 함수에 널 포인터로 파라미터로 넘기려고 했는데 의도하지 않게 컴파일러는 int로 추론하여 func( int a )가 호출 되었습니다.

 

바로 이와 같은 문제를 해결하기 위해서 nullptr 이라는 키워드가 생겼습니다.

 

 

 

nullptr 구현안

 

C++0x에서 nullptr의 드래프트 문서를 보면 nullptr은 아래와 같은 형태로 구현 되어 있습니다.

 

const class {

public:

    template <class T>

    operator T*() const

    {

        return 0;

    }

 

    template <class C, class T>

    operator T C::*() const

    {

        return 0;

    }

 

private:

    void operator&() const;

 

} nullptr = {};

 

 

 

nullptr 사용 방법

 

사용방법은 너무 너무 간단합니다. ^^

그냥 예전에 널 포인터로 0 이나 NULL을 사용하던 것을 그대로 대처하면 됩니다.

 

char* p = nullptr;

 

<List1>에서 널 포인트를 파라미터로 넘겨서 func( double* p )가 호출하게 하기 위해서는

func( nullptr );

로 호출하면 됩니다.

 



nullptr의 올바른 사용과 틀린 사용 예

 

 

올바른 사용

char* ch = nullptr; // ch에 널 포인터 대입.

sizeof( nullptr ); // 사용 할 수 있습니다. 참고로 크기는 4 입니다.

typeid( nullptr ); // 사용할 수 있습니다.

throw nullptr; // 사용할 수 있습니다.

 

 

틀린 사용

int n = nullptr; // int에는 숫자만 대입가능한데 nullptr은 클래스이므로 안됩니다.

 

Int n2 = 0

if( n2 == nullptr ); // 에러

 

if( nullptr ); // 에러

 

if( nullptr == 0 ); // 에러

 

nullptr = 0; // 에러

 

nullptr + 2; // 에러

 

 

 

nullptr 너무 간단하죠? ^^

VC++ 10에서는 예전처럼 널 포인터를 나타내기 위해서 0 이나 NULL 매크로를 사용하지 말고 꼭 nullptr을 사용하여 함수나 템플릿에서 널 포인터 추론이 올바르게 되어 C++을 더 효율적으로 사용하기 바랍니다.^^

 

 

 

짜투리 이야기...... ^^


왜 nullptr 이라고 이름을 지었을까?

nullptr을 만들 때 기존의 라이브러리들과 이름 충돌을 최대한 피하기 위해서 구글로 검색을 해보니 nullptr로 검색 결과가 나오는 것이 별로 없어서 nullptr로 했다고 합니다.

제안자 중 한 명인 Herb Sutter은 현재 Microsoft에서 근무하고 있는데 그래서인지 C++/CLI에서는 이미 nullptr 키워드를 지원하고 있습니다.

 

 

C++0x 이야기

근래에 Boost 라이브러리의 thread 라이브러리가 C++0x에 채택 되었다고 합니다. Boost에 있는 많은 라이브러리가 C++0x에 채택되고 있으므로 컴파일러에서 아직 지원하지 않는 C++0x의 기능을 먼저 사용해 보고 싶다면 꼭 Boost 라이브러리를 사용해 보기 바랍니다.

 


 

참고

http://d.hatena.ne.jp/faith_and_brave/20071002/1191322319

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf

http://ja.wikibooks.org/wiki/More_C%2B%2B_Idioms/nullptr

http://d.hatena.ne.jp/KZR/20080328/p1

 

 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

'Language Development > C++0x' 카테고리의 다른 글

C++0x 관련 책 "Visual C++ 10과 C++0x"  (9) 2010/04/17
VC++ 10에 구현된 C++0x의 코어 언어 기능들  (0) 2010/04/12
nullptr  (0) 2010/01/28
대용량 파일 조작을 위한 C++0x의 변화  (0) 2009/09/07
[VC++] 14. decltype  (0) 2009/06/30
[VC++] 13. Lambda - 네 번째  (1) 2009/06/23

댓글을 달아 주세요

Posted by 흥배

concurrent_queue는 사용 용도가 concurrent_vector 보다 더 많을 것 같아서 좀 더 자세하게 설명하겠습니다.

 

온라인 서버 애플리케이션의 경우 Producer-Consumer 모델이나 이와 비슷한 모델로 네트웍을 통해서 받은 패킷을 처리합니다. 즉 스레드 A는 네트웍을 통해서 패킷을 받으면 Queue에 넣습니다. 그리고 스레드 B Queue에서 패킷을 꺼내와서 처리합니다. 이 때 Queue는 스레드 A B가 같이 사용하므로 공유 객체입니다. 공유 객체이므로 패킷을 넣고 뺄 때 크리티컬섹션과 같은 동기 객체로 동기화를 해야 합니다. 이런 곳에 concurrent_queue를 사용하면 아주 좋습니다.

 

 

concurrent_queue를 사용하기 위한 준비 단계

 

너무 당연하듯이 헤더 파일과 네임스페이스를 선언해야 합니다.

 

헤더파일

#include <concurrent_queue.h>

 

네임스페이스

using namespace Concurrency;

을 선언합니다.

 

이제 사전 준비는 끝났습니다. concurrent_queue를 선언한 후 사용하면 됩니다.

concurrent_queue< int > queue1;

 

 


concurrent_queue에 데이터 추가

 

concurrent_queue에 새로운 데이터를 넣을 때는 push 라는 멤버를 사용합니다.

 

원형

void push( const _Ty& _Src );

 

STL deque push_back과 같은 사용 방법과 기능도 같습니다. 다만 스레스 세이프 하다는 것이 다릅니다. concurrent_queue는 앞 회에서 이야기 했듯이 스레드 세이프한 컨테이너이므로 제약이 있습니다. 그래서 deque 와 다르게 제일 뒤로만 새로운 데이터를 넣을 수 있습니다.

 

concurrent_queue< int > queue1;

queue1.push( 11 );

 

 

 

concurrent_queue에서 데이터 가져오기

 

데이터를 가져올 때는 try_pop 멤버를 사용합니다. 앞의 push의 경우는 STL deque와 비슷했지만 try_pop은 꽤 다릅니다.

 

원형

bool try_pop( _Ty& _Dest );

 

try_pop을 호출 했을 때 concurrent_queue에 데이터가 있다면 true를 반환하고 _Dest에 데이터가 담기며 concurrent_queue에 있는 해당 데이터는 삭제됩니다. 그러나 concurrent_queue에 데이터가 없다면 false를 즉시 반환하고 _Dest에는 호출했을 때의 그대로 됩니다.

 

concurrent_queue< int > queue1;

 

queue1.push( 12 );

queue1.push( 14 );

 

int Value = 0;

 

if( queue1.try_pop( Value ) )

{

           // queue1에서 데이터를 가져왔음

}

else

{

           // queue1은 비어 있었음.

}

 

 

 

concurrent_queue가 비어 있는지 검사

 

concurrent_queue가 비어 있는지 알고 싶을 때는 empty()를 사용합니다. 이것은 STL deque와 같습니다.

 

원형

bool empty() const;

 

비어 있을 때는 true를 반환하고 비어 있지 않을 때는 false를 반환합니다. 다만 empty를 호출할 때 비어 있는지 검사하므로 100% 정확하지 않습니다. 100% 정확하지 않다라는 것은 empty push, try_pop 이 셋은 스레드 세이프하여 동시에 사용될 수 있으므로 empty를 호출할 시점에는 데이터가 있어서 false를 반환했지만 바로 직후에 다른 스레드에서 try_pop으로 삭제를 해버렸다면 empty 호출 후 false를 반환했어 try_pop을 호출했는데 false가 반환 될 수 있습니다.

 

 

 

concurrent_queue에 있는 데이터의 개수를 알고 싶을 때

 

concurrent_queue에 있는 데이터의 개수를 알고 싶을 때는 unsafe_size 멤버를 사용합니다.

 

원형

size_type unsafe_size() const;

 

이것은 이름에서도 알 수 있듯이 스레드 세이프 하지 않습니다. 그래서 unsafe_size를 호출할 때 push try_pop이 호출되면 unsafe_size를 통해서 얻은 결과는 올바르지 않습니다.

 

 


concurrent_queue에 있는 데이터 순차 접근

 

concurrent_queue에 있는 데이터를 모두 순차적으로 접근하고 싶을 때는 unsafe_begin unsafe_end를 사용합니다.

 

원형

iterator unsafe_begin();

const_iterator unsafe_begin() const;

 

iterator unsafe_end();

const_iterator unsafe_end() const;

 

unsafe_begin을 사용하여 선두 위치를 얻고, unsafe_end를 사용하여 마지막 다음 위치(미 사용 영역)를 얻을 수 있습니다. 이것도 이름에 나와 있듯이 스레드 세이프 하지 않습니다.

 

 

 

모든 데이터 삭제


모든 데이터를 삭제할 때는 clear를 사용합니다. 이것은 이름에 unsafe라는 것이 없지만 스레드 세이프 하지 않습니다.

 

원형

template< typename _Ty, class _Ax >

void concurrent_queue<_Ty,_Ax>::clear();

 

 

 

제 글을 보는 분들은 C++을 알고 있다는 가정하고 있기 때문에 STL을 알고 있다고 생각하여 아주 간단하게 concurrent_queue를 설명 하였습니다.

 

concurrent_queue 정말 간단하지 않습니까? 전체적으로 STL deque와 비슷해서 어렵지 않을 것입니다. 다만 스레드 세이프 하지 않은 것들이 있기 때문에 이것들을 사용할 때는 조심해야 된다는 것만 유의하면 됩니다.

 

이것으로 Concurrency Runtime PPL에 대한 설명은 일단락 되었습니다.

이후에는 Concurrency Runtime의 다른 부분을 설명할지 아니면 Beta2에서 새로 추가된 C++0x의 기능이나 또는 이전에 설명한 것들을 더 깊게 설명할지 고민을 한 후 다시 찾아 뵙겠습니다.^^

 

 


참고

Producer-Consumer 모델 : 자바워크님의 http://javawork.egloos.com/2397148

MSDN concurrent_queue :

http://msdn.microsoft.com/en-us/library/dd504906(VS.100).aspx#queue

 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요

Posted by 흥배

concurrent_queuequeue 자료구조와 같이 앞과 뒤에서 접근할 수 있습니다.

concurrent_queue는 스레드 세이프하게 enqueue와 dequeue(queue에 데이터를 넣고 빼는) 조작을 할 수 있습니다.

또 concurrent_queue반복자를 지원하지만 이것은 스레드 세이프 하지 않습니다.

 



concurrent_queuequeue의 차이점


concurrent_queuequeue는 서로 아주 비슷하지만 다음과 같은 다른 점이 있습니다.

( 정확하게는 concurrent_queue와 STL의 deque와의 차이점 이라고 할수 있습니다. )


- concurrent_queue enqueue dequeue 조작이 스레드 세이프 하다.


- concurrent_queue는 반복자를 지원하지만 이것은 스레드 세이프 하지 않다.


- concurrent_queue front pop 함수를 지원하지 않는다.

  대신에 try_pop 함수를 대신해서 사용한다.


- concurrent_queue back 함수를 지원하지 않는다.

  그러므로 마지막 요소를 참조하는 것은 불가능하다.


- concurrent_queue size 메소드 대신 unsafe_size 함수를 지원한다.

  unsafe_size는 이름 그대로 스레드 세이프 하지 않다.


 

 

스레드 세이프한 concurrent_queue의 함수


concurrent_queue에 enqueue 또는 dequeue 하는 모든 조작에 대해서는 스레드 세이프합니다.

 

- empty

- push

- get_allocator

- try_pop

 

empty는 스레드 세이프하지만 empty 호출 후 반환되기 전에 다른 스레드에 의해서 queue가 작아지던가 커지는 경우 이 동작들이 끝난 후에 empty의 결과가 반환됩니다.

 



스레드 세이프 하지 않은 concurrent_queue의 함수

 

- clear

- unsafe_end

- unsafe_begin

- unsafe_size

 

 


반복자 지원

 

앞서 이야기 했듯이 concurrent_queue는 반복자를 지원하지만 이것은 스레드 세이프 하지 않습니다. 그래서 이것은 디버깅 할 때만 사용할 것을 추천합니다.

또 concurrent_queue의 반복자는 오직 앞으로만 순회할 수 있습니다.


concurrent_queue는 아래의 반복자를 지원합니다.

 

- operator++

- operator*

- operator->

 

 

concurrent_queue는 앞서 설명한 concurrent_vector와 같이 스레드 세이프한 컨테이너지만 STL vector deque에는 없는 제약 사항도 있습니다. 우리들이 Vector deque를 스레드 세이프하게 래핑하는 것보다는 Concurrency Runtime에서 제공하는 컨테이너가 성능적으로 더 좋지만 모든 동작이 스레드 세이프하지 않고 지원하지 않는 것도 있으니 조심해서 사용해야 합니다.

 

 

다음에는 일반적인 queue에는 없고 concurrent_queue에서만 새로 생긴 함수에 대해서 좀 더 자세하게 설명하겠습니다.


ps : 앞 주에 Intel의 TBB에 대한 책을 보았습니다. 전체적으로 Concurrency Runtime과 비슷한 부분이 많아서 책을 생각 외로 빨리 볼 수 있었습니다. 제 생각에 TBB나
Concurrency Runtime를 공부하면 다른 하나도 아주 빠르고 쉽게 습득할 수 있을 것 같습니다.
저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글을 달아 주세요