728x90

CUDA는 계산 능력이 1.1 이상의 버전에서 원자적 연산(automic operation)을 지원한다.


하지만, 원자적 연산을 모든 블록의 쓰레드가 동시에 실행하게 되면, 그 원자에 접근하려는 수천 개의 스레드들이 치열한 다툼을 하게 되면서 오히려 성능 저하가 발생하게 된다.


그럴 때에는 공유 메모리를 사용하여, 원자에는 최대한 접근을 하지 않도록 하는 것이 좋다.





728x90

'Parallel Programming > CUDA' 카테고리의 다른 글

CUDA - 스트림(stream)  (0) 2016.03.03
CUDA - 고정 메모리(cudaHostAlloc())  (0) 2016.03.03
CUDA - 시간 측정  (0) 2016.02.26
CUDA - 2차원 배열의 할당과 이용  (0) 2016.02.25
CUDA - 그래픽스 상호운용 - 6  (0) 2016.02.24
728x90

NVIDIA에서 공식적으로 제공하는 방법이다.



위 코드와 같은 방법으로 사용이 가능하다.


우선 두개의 cudaEvent 변수를 생성해야 하는데, 이것은 record 하는 순간의 timestamp를 저장하는 형식이기 때문이다.

이후 cudaEventRecord()를 이용하여 시작하는 순간과 끝나는 순간의 timestamp를 저장하면 된다.

시간은 cudaEventElapsedTime()를 이용하여 받아오는데, cudaEvent는 기본적으로 float으로 반환한다.


cudaEventSynchronize()는 Host에서 사용되는 함수로써, event가 발생할 때까지 Host는 대기하게 된다.

이와 비슷한 함수로 cudaStreamWaitEvent()가 있는데, 이 함수는 Device내부에서 event가 발생할 때까지 대기한다.


728x90
728x90

간단하게 말하면 중단이 불가능한 연산을 의미한다. 문제는 이를 얼마나 이해하는 것인데 자신이 작성한 코드가 원자적 연산이 아닐 수도 있다는 사실을 알아야 한다. 


01: public class Example {
02:      int lastId;
03:      public void resetId() {
04:           lastId=0;
05:      }
06:      public int getNextId() {
07:           ++lastId;
08:      }

4번째 줄은 단순히 0을 lastId에 할당하므로 원자적 연산이다. 그러나 lastId 타입을 long으로 바꾸면 원자적 연산이 아닐 수 있다. 64비트 명령을 지원하기 위해서 JVM은 long을 32비트 명령어 두개로 처리한다. 7번째 줄 역시 원자적 연산이 아니다. ISA를 다 이해할 필요는 없지만 위의 내용 정도는 알아 두는 것이 정신 건강에 좋다.


728x90
728x90

템플릿은 C++을 강력한 언어로 만들어주는 기법 중의 하나입니다.

 

템플릿이라는 문법을 통해서 편리하게 STL을 사용할 수도 있습니다.

 

이 중에 auto_ptr이라는 스마트 포인터가 있습니다. 

 

auto_ptr은 <memory>에 구현되어 있습니다. 

 

제목에서 보이듯이 이 스마트 포인터는 반만 스마트합니다.

 

그 이유를 차근차근 보도록 하겠습니다.

 

auto_ptr은 템플릿 클래스로 만들어져 있기 때문에,

어떤 타입의 포인터든 받을 수 있습니다.

 

클래스의 특징 중 하나는 Scope(유효 범위)를 벗어나면 소멸자가 호출된다는 것인데

 

이 특징을 이용하고 있습니다.

 

만약 다음과 같은 코드가 있다면 메모리의 누수가 생깁니다.

 

void main()

{

        int* pInt = new int;

        *pInt = 10;

        cout<<*pInt<<endl;

        // delete pInt;

}

 

new로 동적할당을 하고 delete를 호출하지 않아서 메모리 누수가 있습니다.

 

void main()

{

        auto_ptr<int> pInt(new int);

        *pInt = 10;

        cout<<*pInt<<endl;

}

 

이렇게 auto_ptr을 사용 가능합니다.

 

<> 안에 사용할 타입을 넣어주시면 됩니다.

 

auto_ptr은 구현을 보시면 소멸자(~auto_ptr())에 다음과 같이 되어 있습니다.

 

~auto_ptr()

{

        delete _Myptr;
}

 

_Myptr은 auto_ptr이 내부적으로 관리하는 포인터입니다.

 

생성자가 동적할당된 주소를 받게 되어 있는데, 그 주소를 가리키는 포인터입니다.

 

Visual Studio에서는 _Ty *_Myptr; 으로 되어 있습니다.

 

템플릿에서 흔히 쓰는 표현으로는 T_Myptr이 됩니다.

 

넘겨받은 주소를 저장하고 갖고 있다가 소멸자가 호출될 때,

 

delete _Myptr; 을 호출하는 것 뿐입니다.

 

여기서 auto_ptr의 한 가지 단점이 나옵니다.

 

동적할당을 배열 단위로 하면 정상적으로 메모리 해제가 안된다.

 

new int [5];로 할당하면 delete[] _Myptr로 바뀌어야 하는데

 

이미 소멸자의 코드는 delete _Myptr;로 고정되어 있습니다.

 

이 경우에는 메모리의 누수를 가져올 수 있습니다.

 

그리고 malloc()으로 할당된 메모리에 대해서도 정상적으로 해제가 안될 수 있습니다.

 

같은 이유로 malloc()은 free()와 쌍을 이뤄야 하기 때문입니다. 

 

이러한 문제를 다른 스마트 포인터는 functor(함수 객체)라는 

 

문법을 사용하여, 회피하고 있습니다. 

 

소멸자에서 호출할 메모리 해제 코드를 직접 지정할 수 있습니다. 

 

그리고 대입 등으로 내부의 포인터를 복사하면 복사가 되는 것이 아니라

 

이전의 auto_ptr은 NULL로 무효화처리 됩니다.

 

a = b;

 

위와 같을 때 일반적으로는 a와 b값이 같아지지만,

 

auto_ptr은 a에 b의 값이 들어가면서 b는 NULL로 바뀌어버립니다.

 

이렇게 되는 이유는 만약 a와 b가 같은 위치를 가리키고 있을 때, a가 먼저 delete로

 

해당 메모리 영역을 해제해버리면 b는 이미 해제된 영역을 다시 delete하기 때문에

 

문제가 생기기 때문입니다.

 

여기서 auto_ptr의 두 번째 단점이 나옵니다.

 

한 곳의 위치를 가리키는 2개의 auto_ptr을 생성할 수 없다.

 

억지로 가리킬 수는 있어도 나중에 해제 시에 반드시 문제가 생기게 됩니다.

 

auto_ptr에 release()라는 메소드가 존재하는데

 

자기가 갖고 있는 포인터를 반납(리턴)하면서 포인터를 NULL로 바꿉니다.

 

그래서 release()를 사용하면, 포인터를 돌려받고, auto_ptr 객체가 무효화 됩니다.

 

그래서 스마트 포인터들은 이 문제를 참조 카운트(Reference Count)를 통해서

 

해결합니다.

 

참조 카운트를 유지하면서 대입을 하거나 했을 때, 카운트를 하나씩 올려주고

 

소멸자가 호출되면, 카운트를 다시 하나씩 내려줍니다.

 

그러다가 마지막에 카운트가 0이 되는 순간 메모리를 해제하는 방법입니다.

 

shared_ptr이 이런 스마트 포인터 중 하나이며  

 

COM에도 이런 기능을 하는 스마트 포인터들이 존재합니다.(CComPtr 등등...) 

또, C++11에서는 auto_ptr에 Deprecated 되었다고 나옵니다.

 

앞으로를 위해서는 auto_ptr은 절대 사용하면 안됩니다.

 

unique_ptr은 auto_ptr을 대체합니다.  

그 외에도 대체할 수 있는 스마트 포인터가 많이 있으므로 다른 스마트 포인터를

 

사용하시면 됩니다.


출처 : http://psychoria.blog.me/40155382971

728x90
728x90

C++03까지는 Null Pointer를 나타내기 위해 NULL 매크로나 상수 0을 사용했다. 그러나 NULL 매크로나 상수 0을 사용하여 함수에 인자로 넘기면 int형으로 추론되어버리는 문제가 발생하기도 한다.


그리하여 nullptr이라는 키워드가 생겼다.


사용 방법은 Null Pointer로 '0'이나 'NULL'을 사용하던 것을 'nullptr'로 바꾸기만 하면된다.

char* p = nullptr;




728x90
728x90

enum은 C++에서 이미 있는 키워드이다. 그러나 C++11에서는 C++03 표준과 달리 'unscoped enumeration'과 'scoped enumeration' 두 종류의 enum으로 바뀌었다.


1. unscoped enumeration은 기존(C++03) enum과 비슷하다. unscoped enumeration은 다음과 같이 정의한다.


2. scoped enumeration은 다음과 같이 정의 한다.


ps. enum class 대신 enum struct를 사용할 수도 있다.



728x90
728x90

이 range based for는 Visual C++(VC)의 특화 기능인 'for each'문과 비슷하다.



당연히 STL에서도 사용이 가능하다. 그러므로 STL의 Iterator를 지원하는 컨테이너라면 'range based for'를 활용하여 편하게 사용하도록 하자.


for( auto i : arrNumberList )의 경우에는 i의 값을 for문 안에서는 변경할 수 있찌만, for 문을 나오면 arrNumberList의 요소에는 적용되지 않는다. 


만약 요소의 값을 변경하고 싶다면 참조를 사용하면된다. for( auto& i : arrNumberList )


또한 for문에서 요소 값을 변경하지 못하도록 하려면 const를 사용하면 된다. for(auto const i : arrNumberList)


마지막으로 for문에서 데이터셋 요소에 접근할 때 임시 변수를 만드므로 이 비용을 줄이고 싶다면, 참조를 사용하는 게 좋다.

만약 요소 값을 변경하지 못하게 하고 싶다면 const 참조를 사용하면 된다. for(auto const &i : arrNumberList)





728x90

'Basic Programming > C++ 11' 카테고리의 다른 글

C++11 - nullptr  (0) 2016.02.26
C++11 - enum  (0) 2016.02.26
C++11 - 람다(lambda) 함수 - 2  (0) 2016.02.25
C++11 - 람다(lambda) 함수 - 1  (0) 2015.12.08
C++11 - auto 키워드  (0) 2015.12.08
728x90

람다를 사용할 때 람다 외부에 정의되어 있는 변수를 람다 내부에서 사용하고 싶으면 그 변수를 캡쳐(Capture)하면 된다. 캡처는 참조나 복사로 전달이 가능하다. 참조로 할 때는 '&'를, 복사로 전달할 때는 '변수 이름'을 기술한다.


람다 표현의 '[ 람다 캡쳐 ] ( 파라미터 ) { 식 }' 중에서 맨 앞의 '[ 람다 캡쳐 ]'에 캡처할 변수를 기술한다.


다음과 같이 '[ &v1, &v2 ]' 사용하면 복수의 변수를 캡처할 수 있다.


또한 다음과 같이 '[&]' 사용하면 람다 외부의 모든 변수를 참조로 캡처할 수 있다.



728x90

'Basic Programming > C++ 11' 카테고리의 다른 글

C++11 - nullptr  (0) 2016.02.26
C++11 - enum  (0) 2016.02.26
C++11 - range based for  (0) 2016.02.25
C++11 - 람다(lambda) 함수 - 1  (0) 2015.12.08
C++11 - auto 키워드  (0) 2015.12.08

+ Recent posts