SlideShare a Scribd company logo
1 of 100
Dev306




認識 C++11 新標準
及使用 AMP 函式庫
作平行運算
王建興
qing.chwang at gmail.com
講者簡介
現職
 聖藍科技技術長
興趣
 網路應用系統開發
譯作
 Thinking in Java 4th Edition, 正體中文版
 Thinking in Java 2nd Edition, 正體中文版
 Essential C++, 正體中文版
專欄
 iTHome 電腦報程式人專欄
連絡方式:qing at gmail.com
Agenda
 C++新標準 - C++11
 使用C++ AMP做平行運算
C++新標準- C++11
C++11
 C++11,先前被稱作C++0x,即ISO/IEC
 14882:2011
 C++11,是目前的C++程式語言的正式標準
  取代第二版標準ISO/IEC 14882:2003
 在2011年八月正式成為標準,故名為C++11
C++11要達成的目標
 讓C++成為在系統程式設計以及程式庫設計
 領域中較好的程式語言
  直接使用C++而非為特定應用領域提供專門的開
  發語言
 使C++更易於教導及學習
  增加一致性、加強安全性、為初學者提供相關的
  機制
 如何達成
  在維持效能甚至提升效能的同時,提供更高階、
  更抽象化

   *http://www.stroustrup.com/C++11FAQ.html#aims
C++ 11中的增進 – Core Language

 執行時期的效能增進,例如:
  rvalue reference
  對POD定義的修改
 建構時期的效能增進,例如:
  extern template
 使用性的加強,例如:
  型別的推論
  Range-based for-loop
 功能的改進,例如
  static assertion
C++ 11 -從 VC10 到 VC11 (1/3)
C++ 11 -從 VC10 到 VC11 (2/3)
C++ 11 -從 VC10 到 VC11 (3/3)
Concurrency – 從 VC10 到 VC11
今天要談的 C++11 特色 (1/2)
 Right angle brackets
 extern template
 enum Class
 POD定義的修改
 區域及不具名的型別做為模版的參數
 Range-for述句
今天要談的 C++11 特色 (2/2)
 auto Keyword
 decltype Type Specifier
 Lambda Expressions
 rvalue references
 static_assert
 nullptr
Right Angle Brackets
list<vector<string>> lvs;

 在C++98中,這是語法錯誤的寫法
 編譯器會將 >> 認為是運算子 >>
 新編譯器將能理解此種語法
extern template
       避免多重實例化模版,明確指定模版於它處
       實例化
       編譯器毋需重複實例化,待鏈結時期再尋找
       實例化後的程式碼即可
#include "MyVector.h"
extern template class MyVector<int>; // Suppresses implicit instantiation below --
                        // MyVector<int> will be explicitly instantiated elsewhere
void foo(MyVector<int>& v)
{
   // use the vector in here
}

-------------------------------------------

#include "MyVector.h"
template class MyVector<int>; // Make MyVector available to clients (e.g., of the shared library

                        *http://www.stroustrup.com/C++11FAQ.html#extern-templates
                        *http://zevoid.blogspot.tw/2012/04/c11-extern-template.html
傳統C++在enum上的問題
 傳統的enum在轉型時會被自動視為int,不
 符合此規則時則會引發錯誤
 傳統的enum其列舉值在其外圍的程式碼範
 圍內皆為可見,這易於產生名稱上的衝突
 無法指定enum的底層型別,容易造成誤解
 以及相容性的問題
 無法進行先行宣告



   http://www.stroustrup.com/C++11FAQ.html#enum
enum class(更高階的enum)
 Scoped and Strongly typed enums
 VC10中並未支援,VC11已支援
    enum Alert { green, yellow, election, red };

    enum class Color { red, blue };

    enum class TrafficLight { red, yellow, green };

    Alert a = 7;
    Color c = 7;
    int a2 = red;
    int a3 = Alert::red;
    int a4 = blue;
    int a5 = Color::blue;

    Color a6 = Color::blue;
     Error Error in C++98; OK in C++11
指定enum的底層型別
  並同時決定enum的佔用空間
  在過去,佔用空間取決於實作而定
  底層型別必須是整數型的型別,預設為int
enum class Color : char { red, blue };

enum class TrafficLight { red, yellow, green };

enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U }; // how big is an E?

enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U };
enum的先行宣告
  C++11中可以做先行宣告了

enum class Color_code : char;
void foobar(Color_code* p);
// ...
enum class Color_code : char { red, yellow, green, blue };
enum Class的意義
 讓列舉型別的表示方式更高階、更抽象、更
 直覺
 即使是C++的後繼者Java,一開始也沒有專
 門的enum type,而是在J2SE 5.0之後加入
對POD定義的修改
  POD(Plain Old Data)
  符合這種定義的型別能夠允許產生與C相容
  的物件佈局
  在C++98,POD指的是像C中struct那樣的資
  料
      能使用memcpy()
      能使用memset()進行初始化
struct S { int a; };                           // S is a POD
struct SS { int a; SS(int aa) : a(aa) { } };   // SS is not a POD
struct SSS { virtual void f(); /* ... */ };
C++11中的POD
struct S { int a; };                           // S is a POD
struct SS { int a; SS(int aa) : a(aa) { } };   // SS is a POD
struct SSS { virtual void f(); /* ... */ };

  在C++11中,SS也是個POD
      建構式並不影響
  SSS 不會是POD,因為會有個虛擬函式表
  C++定義POD是可複製的型別、極簡型別、
  以及具有標準佈局的型別
  VC10中並未支援,VC11已支援
極簡(trivial)型別或結構
 極簡的預設建構式。這可以使用預設建構式
 語法
  例如SomeConstructor() = default;
 極簡的複製建構式,可使用預設語法
 極簡的賦值運算子,可使用預設語法
 極簡的解構式,不可以是虛擬的




         *http://zh.wikipedia.org/zh-tw/C%2B%2B11
標準佈局(standard-layout)的型別或結構
 只有非靜態的資料成員,且這些成員也是符
 合標準佈局的型別
 對所有非靜態成員有相同的存取控制
 沒有虛擬函式,也沒有虛擬基礎類別
 只有符合標準佈局的基礎類別
 沒有和第一個定義的非靜態成員相同型別的
 基礎類別
 若非沒有帶有非靜態成員的基礎類別,就是
 最底層(繼承最末位)的型別沒有非靜態資料
 成員而且至多一個帶有非靜態成員的基礎類
 別。基本上,在該型別的繼承體系中只會有
 一個型別帶有非靜態成員
POD的標準
Class/struct/union被視為是POD要滿足三個
條件
 它是極簡的型別或結構
 它是標準佈局的型別或結構
 其所有資料成員及基礎類別皆為PODs
區域及不具名的型別做為模版的參數

  在C++98,區域及不具名的型別不能做為模
  版的參數傳入
  如今,在C++11中支援了
     一致性更好
void f(vector<X>& v)
{
        struct Less {
                bool operator()(const X& a, const X& b)
                { return a.v<b.v; }
        };
        sort(v.begin(), v.end(), Less()); // C++98: error: Less is local
                                                          // C++11: ok
}
         *http://www.stroustrup.com/C++11FAQ.html#local-types
不具名型別的值也能做為模版參數

template<typename T> void foo(T const& t){}
enum X { x };
enum { y };

int main()
{
      foo(x);           // C++98: ok; C++11: ok
      foo(y);           // C++98: error; C++11: ok
      enum Z { z };
      foo(z);           // C++98: error; C++11: ok
}
auto Keyword (1/3)
 auto 關鍵字能從所宣告變數的初始算式,導
 出其型別 ( 當然是編譯時期 )

  auto declarator initializer;

  int j = 0;
  auto k = 0; // Variable k is implicitly type int




       *http://msdn.microsoft.com/en-us/library/dd293667(v=VS.100).aspx
auto Keyword (2/3)

  map<int,list<string>>::iterator i = m.begin();
  auto i = m.begin();

  auto x = 1, *y = &x, **z = &y;     // Resolves to int.
  auto a(2.01), *b (&a);              // Resolves to double.
  auto c = 'a', *d(&c);              // Resolves to char.
  auto m = 1, &n = m;                 // Resolves to int.
auto Keyword (3/3)
 使用 auto 關鍵字時的重要限制
 使用時一定要搭配 initializer
 不能用來宣告陣列、變數的 return type、函
 式或 template 的參數
 除了 static member 之外,不能在
 class/struct 中使用 auto 宣告 data member
錯誤的 auto 使用

auto a;
auto ary[10];
auto ary2[] = { 1, 2, 3}
auto foo();
void bar(auto a);
struct A
{
   auto a;
};
使用 auto 的時機
 當資料型別可能隨著編譯器或目標平台而異
 時
  例 strlen() 的回傳型別
 當資料型別過於複雜不易表示時
  例 map<int,list<string>>::iterator i
 將 Lambdas 指派至變數時 ( 待續,
 Lambdas 算式 )
 指定 Trailing Return Types ( 待續, decltype
 )
auto vs. auto
 /Zc:auto[-] 編譯器選項是用來告訴編譯器看
 待宣告變數時 auto 這個關鍵字的確切意義
 指定 /Zc:auto 編譯器會從所宣告變數的初始
 算式推導出其確型別
 指定 /Zc:auto- 編譯器會以 automatic
 storage class 來宣告變數
 此為相容性問題



      *http://msdn.microsoft.com/en-us/library/dd293615.aspx
decltype Type Specifier (1/2)
 decltype 是個 type specifier
 decltype 依據所給定的算式來決定型別
  decltype( expression )
 decltype 不同於 typeid,因為它是從算式中
 得到型別本身,而非型別資訊
decltype Type Specifier (2/2)
  int var;
  const int&& fx();
  struct A { double x; }
  const A* a = new A();

  decltype(fx());   // const int &&
  decltype(var)     // int
  decltype(a->x)    // double ( The type of the member
                     access )
  decltype((a->x)) // const double && (an expression
                   instead of a member access )
使用 decltype 的時機
 適當的表示資料型別
 decltype(mstr.begin()->second.get_allocator()) under_alloc;

 decltype 和 auto 不同的是,auto 推導型別
 是靠初始算式,得發生指派動作
 decltype 只是從算式評估結果的型別來推導
 型別,但卻不會確切的進行評估
 decltype(mstr.begin()->second.get_allocator()) under_alloc;
trailing-return-type

auto function_name( parameters ) −> decltype( expression )
{
  function_body;
}
template<typename T, typename U>
auto myFunc( T& t, U& u)-> decltype( t + u ){
 return t + u;
};
C++11對型別推論的加強
 auto及decltype 其作用皆是在編譯時期推論
 型別
 編譯器在編譯時期確切的能從變數的初始化
 述句以及算式得到最終該有的型別
 編譯時期的動作不影響執行時期的效能
  C++的一貫哲學
 之所以要有型別推論不是因為那些顯而易見
 的型別宣告問題
  長久以來C++程式設計者受模版庫中複雜的型別
  宣告所苦
   它們確切究竟是什麼型別並不那麼重要
Ranged-for
 透過Ranged-for 述句,可以在迴圈裡遞代一
 組元素
 所有標準的容器、 std::string 、初始化列表
 、陣列、以及所有可以定義begin()及end()的
 類別都可適用
 void f(vector<double>& v)
 {
        for (auto x : v) cout << x << 'n';
        for (auto& x : v) ++x;
 }

 for (const auto x : { 1,2,3,5,8,13,21,34 }) cout << x << 'n';

          *http://www.stroustrup.com/C++11FAQ.html#aims
Ranged-for 的意義
 提供更高階的迴圈語義
 Compiler Sugar
 即使如Java,也在J2SE 5.0之後,加入了
 forech的語法
Lambda Expressions(1/4)
 基本上就像是個匿名函式(anonymous
 function)
  []() mutable throw() -> typeid
  {
    //function body
  }
 Lambda Expression 使得函式可以在使用的
 地方定義,並且可以在Lambda 函式中使用
 Lambda 函式之外的變數
 比函式物件或函式指標方便且單純
Lambda Expressions(2/4)
 1.capture clause
 2.parameter list
 3.mutable specification
 4.exception specification
 5.return type
 6.lambda body
Lambda Expressions (3/4)
capture clause




      *http://heresy.spaces.live.com/blog/cns!E0070FB8ECF9015F!10575.entry
Lambda Expressions (4/4)
parameter list
  不能有預設引數
  不能有可變長度引數列表
  不能有不具名參數
  沒有參數時,可省略 parameter list
   int main()
   {
     int x = 4;
     int y = 5;
     int z = [=] { return x + y; } ;
   }
使用函式物件

struct FunctionObj {
   void operator()(int n) const {
       // 對n操作
   }
}
…
for_each(v.begin(), v.end(), FunctionObj ());
使用Lambda Expression

for_each(v.begin(), v.end(), [] (int n) {
      // 操作 n
}
rvalue references
 rvalue reference 被創造,其中最大的意義
 之一,便是為了提供更有效率的 move 語義
 rvalue reference 語法

  type-id && cast-expression




        *http://msdn.microsoft.com/en-us/library/dd293668(v=VS.100).aspx
lvalue & rvalue (1/2)
  每個算式,若非 lvalue 便為 rvalue
  lvalue 指的是在單一算式之後所代表的一個
  續存物件
     例:++x
  rvalue 指的是在算式評估結束之後,生命期
  便結束的暫時性物件
     例:x++
  能對它取址的即為 lvalue


 *http://blogs.msdn.com/b/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx
lvalue & rvalue (2/2)

string one("cute");
const string two("fluffy");
string three() { return "kittens"; }
const string four() { return "are an essential part of a
healthy diet"; }

one; // modifiable lvalue
two; // const lvalue
three(); // modifiable rvalue
four(); // const rvalue
C++ 的複製問題
  每次 + 運算子執行時,都會產生一個暫時性
  物件
string s0("my mother told me that");
string s1("cute");
string s2("fluffy");
string s3("kittens");
string s4("are an essential part of a healthy diet");

string dest = s0 + " " + s1 + " " + s2 + " " + s3 + " " + s4;
                                產生了八個暫時性物件!
問題出在那裡?
因為 s0 是個 lvalue 不能加以修改,所以在
計算 s0 + “ “ 時,得建立一暫時物件
但在接著計算 (s0 + “ ”) + s1 時,可以直接
把 s1 接到之前建立的暫時物件後,便毋需
再產生第二個暫時物件,並捨棄第一個暫時
物件
這便是 move 語義的核心觀念
move 語義的實作 (1/2)
 在 C++11 中,每次 + 運算子被呼叫時,仌
 會產生獨立的暫時物件
 但第二次呼叫 + 運算子時(例如在((s0 + “
 ”) + s1)中),會將前一個暫時物件所配置
 的記憶體挪過來使用
 只更動第二個暫時物件指標之值,而不重新
 配置並複製
 第一個暫時物件的指標則指向 null,避免解
 構時的相關行為
move 語義的實作 (2/2)
 所以,若能偵測到處理的是 non-const
 rvalue 時,就可以直接挪用其記憶體
  反正它很快就要被摧毀,又沒人在乎它
 從 rvalue 建立物件,或指派 rvalue 物件之
 值至另一物件時,所謂的 moving,便是挪
 用其記憶體的動作
 例如 vector 要擴展空間時,moving 就很重
 要
 那問題就是在於要如何偵測了!
rvalue reference
 C++11 引入了名為 rvalue reference 的新
 reference,其語法為 Type&& 及 const
 Type&&
 rvalue reference 與 lvalue reference 是不同
 的型別
 但在語意上都一樣是 reference
兩種 reference 在函式重載時的不同行為

 Type& 只能繫結到 non-const lvalue
 const Type& 可以繫結到任何東西
 Type&& 可以繫結到 non-const lvalue 及
 non-const rvalue
 const Type&& 可以繫結到任何東西
rvalue reference 的overload resolution
void purr(const string& s) {
   cout << "purr(const string&): " << s << endl;
}
void purr(string&& s) {
   cout << "purr(string&&): " << s << endl;
}
string strange() {
   return "strange()";
}
const string charm() {
   return "charm()";
}

int main() {
   string up("up");
   const string down("down");

    purr(up);                                // purr(const string&): up
    purr(down);                              // purr(const string&): down
    purr(strange());                         // purr(string&&): strange()
    purr(charm());                           // purr(const string&): charm()
}
提供 move 語義
 傳統的 copy 建構子
 Simple(const Simple&);
 C++0x 中的 move 建構子
 Simple(Simple&&);
 編譯器並不會提供預設的 move 建構子




      *範例取自 http://www.codeproject.com/KB/cpp/cpp10.aspx#RValues
move 建構子被呼叫

Simple GetSimple()
{
  Simple sObj(10);
  return sObj;
}
實作 move 建構子(1/2)
class Simple
{
   // The resource
   void* Memory;

public:

     Simple() { Memory = nullptr; }

     // The MOVE-CONSTRUCTOR
     Simple(Simple&& sObj)
     {
        // Take ownership
        Memory = sObj.Memory;

         // Detach ownership
         sObj.Memory = nullptr;
     }
};
實作 move 建構子(2/2)

Simple(int nBytes)
  {
    Memory = new char[nBytes];
  }

     ~Simple()
     {
       if(Memory != nullptr)
          delete []Memory;
     }
};
move 指派運算子
 傳統的 copy 指派運算子
 void operator=(const Simple&);
 C++0x 中的 move 指派運算子
 void operator=(Simple&&);
實作 move 指派運算子
class Simple
{
  ...
  void operator = (Simple&& sOther)
  {
      // De-allocate current
      delete[] Memory;

       // Take other's memory contnent
       Memory = sOther.Memory;

       // Since we have taken the temporary's resource.
       // Detach it!
       sOther.Memory = nullptr;
  }
};};
rvalue reference的引入
 減尐了一些執行時期額外的記憶體配置以及
 重覆複製資料的負擔
 對提升運行效能有所幫助
 尤其對程式庫中的類別而言
static_assert Declaration (1/2)
  在編譯時期針對指定條件檢驗是否成立
  static_assert(
     constant-expression,
     string-literal
  );
  constant-expression: 若值評估為 0,則編譯
  失敗並顯示string-literal參數之值,反之,則
  無任何影響
static_assert Declaration (2/2)
  應用:

  static_assert(
   sizeof(void *)==4,
   "64-bit code generation is not supported.");
static_assert 與傳統方式的比較
 在過去有兩種檢查方式
  條件編譯 + #error 指令 ( 在 preprocessing 階段
  )
  assert 巨集 ( 在 runtime )
 #error 無法針對 template 參數進行檢查,因
 為 class 是在編譯時才會被 instantiated
 static_assert 是在編譯時期進行檢查,所以
 可以處理 template 參數的檢查
nullptr Keyword
 nullptr 關鍵字用來表示指向空值的指標
 解決 0 和指向空值指標的混淆情況
 提供更直觀更不易出錯的空指標表示方式
  void f(int){ printf( "intn" ); }
  void f(char*){ printf( "char*n" ); }

  f( NULL ); // int, compile error in GCC
  f( 0 ); // int
  f( (char*)0 ); // char*
  f( (void*)0 ); // compile error

      *http://heresy.spaces.live.com/blog/cns!E0070FB8ECF9015F!10891.entry
概括C++11的加強方向
 增加編譯、鏈結時的效能
 增加實際執行的效能
 提供更高階、更抽象的程式設計方式
 提供更簡便、更不易出錯的程式設計方式
使用C++ AMP做平行運算
何謂 C++ AMP?
 AMP: Accelerated Massive Parallelism
   在一個或多個的加速器上執行計算
   目前,實際的加速器就是GPU
   未來,會有其他型式的加速器
 有了C++ AMP後,可以完全使用C++撰寫應
 用程式來獲得平行計算的加速
   可加速數十倍或更多
 AMP 基本上是個程式庫
   附於Visual Studio 2012中
   規格開放,其他平台或編譯器亦可實作
C++ AMP的設計原則
 基於C++而非C
 能成為主流
  愈簡化的程式設計模型愈好
 盡可能尐的改動
 具可攜性
  可於任何廠商的硬體上執行
 通用且不會過期
  使用不同的加速器,例如雲端上的加速器
 開放
  規格開放
CPU vs. GPU



 較低的記憶體頻寬     較高的記憶體頻寬
 高耗能          低耗能
 中度平行化        高度平行化
 較深的指令管線      較淺的指令管線
 隨機存取         循序存取
 支援通用型的程式     支援平行資料操作的程
 通用型的程式設計     式
              專用型的程式設計
GPGPU
 General-Purpose computing on Graphics
 Processing Units
 也稱GP²U
 傳統的GPU通常是處理和圖形有關的計算
 由於現代GPU具有強大的並行處理能力,使
 得GPU也可以用來處理一些通用類型的資料
  尤其是面對單一指令多資料流(SIMD)的情況
 目前,
  OpenCL是現存的GPGPU計算語言
  Nvidia的CUDA則是現成的封閉式框架
異質性計算(Heterogeneous Computing)


 在同一計算系統中,使用不同指令集和架構
 的計算單元來組成計算方式,即為異質性計
 算
 常見的計算單元包括像是
   CPU, GPU, DSP, ASIC, FPGA … 等等
 不同類型計算單元的長處各不盡相同
 異質性計算則嘗試綜合各自的長處
   例如GPU擅長平行計算
 組合CPU+GPU計算的系統,即屬異質性計
 算系統
GPU所能容納的執行緒數-例
NVIDIA GTX 690
 16個多處理器
 每個多處理器有192個CUDA核心
 每個多處理器的最大執行緒數是2048
 可同時容納最多32,768個執行緒
NVIDIA GTX 560 SE
 9個多處理器
 每個多處理器有32個CUDA核心
 每個多處理器的最大執行緒是1536
 可以同時容納最多13,824個執行緒
    *http://www.infoq.com/cn/articles/cpp_amp_computing_on_GPU
程式庫型式的C++ AMP (1/2)

 附於Visual Studio 2012之中
 是個STL-like的程式庫
 #include <amp.h>後取用
 Namespace: concurrency
 新類別
  array, array_new
  extent, index
  accelerator, accelerator_new
程式庫型式的C++ AMP (2/2)

 新函式
  parallel_for_each()
 新關鍵字(或說同名但新的用法)
  restrict
  用來告訴編譯器檢查GPU(DirectX)
parallel_for_each
 程式庫的入口
 接收參數
   所需的執行緒數
   在每個執行緒中執行的函式或labmda(必須是
   restrict(amp))
 將工作送至加速器
 返回 – 不會有遲滯或等待
Hello AMP: 陣列相加
                                        #include <amp.h>
                                        using namespace concurrency;

void AddArrays(int n, int * pA, int *   void AddArrays(int n, int * pA, int *
pB, int * pSum)                         pB, int * pSum)
{                                       {
                                          array_view<int,1> a(n, pA);
                                          array_view<int,1> b(n, pB);
                                          array_view<int,1> sum(n, pSum);

    for (int i=0; i<n; i++)                 parallel_for_each(
                                               sum.extent,
                                               [=](index<1> i) restrict(amp)
    {                                          {
         pSum[i] = pA[i] + pB[i];                sum[i] = a[i] + b[i];
    }                                          }
                                            );
}                                       }
C++ AMP程式設計的基本元素
void AddArrays(int n, int * pA, int * pB, int * pSum)   array_view
{                                                          將資料包裝成可於
  array_view<int,1> a(n, pA);                              加速器上操作的型
  array_view<int,1> b(n, pB);                              式
  array_view<int,1> sum(n, pSum);                       parallel_for_each
                                                           在每個執行緒上執
    parallel_for_each(                                     行一次函式或
                                                           lambda
           sum.extent,
           [=](index<1> i) restrict(amp)
                                                        extent
           {                                               執行lambda的執行
                                                           緒個數及結構形狀
                sum[i] = a[i] + b[i];
           }
                                                        index
    );                                                     執行labmda的執行
                                                           緒ID,做為資料的
}                                                          索引
                                 操作                     restrict(amp)
                                                           表示amp限制
extent<N>: N維空間的大小
index<N>: N維空間中的點
array_view<T, N>
              vector<int> v(10);
 檢視CPU或GPU
 上既存的資料
               extent<2> e(2,5);
 元素型別T,並有      array_view<int,2> a(e, v);
 N維
 需指定extent
 矩形
              //above two lines can also be written
 隨處可存取(自動
              //array_view<int,2> a(2,5,v);
 同步)
              index<2> i(1,3);

              int o = a[i]; // or a[i] = 16;
              //or int o = a(1, 3);
restrict(amp)的限制
 僅能呼叫其他同為restrict(amp)的函式
 所有的函式都必須是可inline
 僅能使用支援amp的型別
  int, unsigned int, float, double, bool
  上述型別構成的struct 及陣列
 指標及參照的限制
  Lambda不能是capture by reference或是
  capture pointer
  參照及單向指標僅能做為區域變數及函式的引數
restrict(amp)的限制
array<T, N>
                          vector<int> v(8 * 12);
                          extent<2> e(8,12);
 多維陣列,元素型別T,              accelerator acc = …
 N維                       array<int,2> a(e,acc.default_view);
 存於特定加速器中的儲存              copy_async(v.begin(), v.end(), a);
 空間
 Capture by reference
 自行指定的複製動作              parallel_for_each(e, [&](index<2> idx)
 和array_view<T, N>相近                          restrict(amp)
 的介面                    {
                            a[idx] += 1;
                        });
                        copy(a, v.begin());
parallel_for_each的非同步特性
 呼叫完立即返回
 當嘗試透過array_view存取處理中的資料時
 ,若尚未運行完畢,則會等待,直到運算結
 束為止
 可運用array_view的synchronize_async()函
 式來處理計算的完成事件
  std::shared_future<void> synchronize_async() const;
撰寫C++ AMP程式簡單直覺
 撰寫C++ AMP程式的步驟
  建立arr​​ay_view物件
  呼叫parallel_for_each
  利用array_view物件得到計算結果
 CPU和GPU之間的溝通細節,皆由程式庫包
 裝
  記憶體的分配和釋放
  資料的同步
  GPU執行緒的規劃和管理
Visual Studio 2012對C++ AMP的除錯支援

 中斷點
 偵錯類型
 變數值及call stack的察看
 GPU的執行緒狀態
 平行計算資料的察看
中斷點的設定
可停在CPU或GPU的中斷點
GPU的中斷點僅Windows 8支援




  *Kate Gregory, “C++ Accelerated Massive Parallelism in Visual C++ 2012”
除錯類型設定
變數值及call stack的察看
GPU的執行緒狀態察看
平行計算資料的察看
開發/執行C++ AMP的條件
 開發
  Visual Studio 2012
  支援DirectX 11的顯示卡
  Windows 8作業系統
 執行
  Windows 7/Windows 8
  支援DirectX 11的顯示卡
看待C++ AMP程式的效能問題
 愈包裝的夠高階夠抽象的程式庫愈有提升效
 能的可能性
 基於C++ AMP的程式本身結構夠簡單
 效能取決於C++ AMP程式庫的實作
 當然還有底層的硬體條件
 只要程式庫被專家最佳化了,應用程式就變
 快了
http://www.microsoft.com/taiwan/techdays2012/
                                                   http://www.microsoft.com/learning/zh/tw/




 http://social.technet.microsoft.com/Forums/zh-   http://social.msdn.microsoft.com/Forums/zh-
                   tw/categories/                                 tw/categories/
認識 C++11 新標準及使用 AMP 函式庫作平行運算
認識 C++11 新標準及使用 AMP 函式庫作平行運算
認識 C++11 新標準及使用 AMP 函式庫作平行運算

More Related Content

What's hot

What's hot (20)

竞赛中C++语言拾遗
竞赛中C++语言拾遗竞赛中C++语言拾遗
竞赛中C++语言拾遗
 
Lua 语言介绍
Lua 语言介绍Lua 语言介绍
Lua 语言介绍
 
Ch10
Ch10Ch10
Ch10
 
Gobject - Inherit (Chinese)
Gobject - Inherit (Chinese)Gobject - Inherit (Chinese)
Gobject - Inherit (Chinese)
 
C語言 第4章 基本輸出與輸入功能
C語言 第4章 基本輸出與輸入功能C語言 第4章 基本輸出與輸入功能
C語言 第4章 基本輸出與輸入功能
 
Ch02
Ch02Ch02
Ch02
 
Ch07
Ch07Ch07
Ch07
 
C++模板与泛型编程
C++模板与泛型编程C++模板与泛型编程
C++模板与泛型编程
 
10 檔案說明與處理
10 檔案說明與處理10 檔案說明與處理
10 檔案說明與處理
 
Ch 8
Ch 8Ch 8
Ch 8
 
Java Script 引擎技术
Java Script 引擎技术Java Script 引擎技术
Java Script 引擎技术
 
07 陣列與字串
07 陣列與字串07 陣列與字串
07 陣列與字串
 
C++11 smart pointers
C++11 smart pointersC++11 smart pointers
C++11 smart pointers
 
xwz 2010-10-31
xwz 2010-10-31xwz 2010-10-31
xwz 2010-10-31
 
第4章函数
第4章函数第4章函数
第4章函数
 
Python基本資料運算
Python基本資料運算Python基本資料運算
Python基本資料運算
 
Python 迴圈作業
Python 迴圈作業Python 迴圈作業
Python 迴圈作業
 
Ch08
Ch08Ch08
Ch08
 
Python分支作業
Python分支作業Python分支作業
Python分支作業
 
Ch03
Ch03Ch03
Ch03
 

Viewers also liked

全文搜尋引擎的進階實作與應用
全文搜尋引擎的進階實作與應用全文搜尋引擎的進階實作與應用
全文搜尋引擎的進階實作與應用建興 王
 
C++11 concurrency
C++11 concurrencyC++11 concurrency
C++11 concurrencyxu liwei
 
開發實用創新的 Android 應用程式
開發實用創新的 Android 應用程式開發實用創新的 Android 應用程式
開發實用創新的 Android 應用程式建興 王
 
開放原始碼的回收與再利用
開放原始碼的回收與再利用開放原始碼的回收與再利用
開放原始碼的回收與再利用建興 王
 
lwdba – 開放原始碼的輕量級資料庫存取程式庫
lwdba – 開放原始碼的輕量級資料庫存取程式庫lwdba – 開放原始碼的輕量級資料庫存取程式庫
lwdba – 開放原始碼的輕量級資料庫存取程式庫建興 王
 
IKVM.NET 深入敵營的 Java
IKVM.NET 深入敵營的 JavaIKVM.NET 深入敵營的 Java
IKVM.NET 深入敵營的 Java建興 王
 
在雲端上啜飲爪哇
在雲端上啜飲爪哇在雲端上啜飲爪哇
在雲端上啜飲爪哇建興 王
 
從 Java programmer 的觀點看 ruby
從 Java programmer 的觀點看 ruby從 Java programmer 的觀點看 ruby
從 Java programmer 的觀點看 ruby建興 王
 
「沙中撈金術」﹣談開放原始碼的推薦系統
「沙中撈金術」﹣談開放原始碼的推薦系統 「沙中撈金術」﹣談開放原始碼的推薦系統
「沙中撈金術」﹣談開放原始碼的推薦系統 建興 王
 
排隊應用開發
排隊應用開發排隊應用開發
排隊應用開發建興 王
 

Viewers also liked (10)

全文搜尋引擎的進階實作與應用
全文搜尋引擎的進階實作與應用全文搜尋引擎的進階實作與應用
全文搜尋引擎的進階實作與應用
 
C++11 concurrency
C++11 concurrencyC++11 concurrency
C++11 concurrency
 
開發實用創新的 Android 應用程式
開發實用創新的 Android 應用程式開發實用創新的 Android 應用程式
開發實用創新的 Android 應用程式
 
開放原始碼的回收與再利用
開放原始碼的回收與再利用開放原始碼的回收與再利用
開放原始碼的回收與再利用
 
lwdba – 開放原始碼的輕量級資料庫存取程式庫
lwdba – 開放原始碼的輕量級資料庫存取程式庫lwdba – 開放原始碼的輕量級資料庫存取程式庫
lwdba – 開放原始碼的輕量級資料庫存取程式庫
 
IKVM.NET 深入敵營的 Java
IKVM.NET 深入敵營的 JavaIKVM.NET 深入敵營的 Java
IKVM.NET 深入敵營的 Java
 
在雲端上啜飲爪哇
在雲端上啜飲爪哇在雲端上啜飲爪哇
在雲端上啜飲爪哇
 
從 Java programmer 的觀點看 ruby
從 Java programmer 的觀點看 ruby從 Java programmer 的觀點看 ruby
從 Java programmer 的觀點看 ruby
 
「沙中撈金術」﹣談開放原始碼的推薦系統
「沙中撈金術」﹣談開放原始碼的推薦系統 「沙中撈金術」﹣談開放原始碼的推薦系統
「沙中撈金術」﹣談開放原始碼的推薦系統
 
排隊應用開發
排隊應用開發排隊應用開發
排隊應用開發
 

Similar to 認識 C++11 新標準及使用 AMP 函式庫作平行運算

Go语言: 互联网时代的C
Go语言: 互联网时代的CGo语言: 互联网时代的C
Go语言: 互联网时代的CGoogol Lee
 
Metro Style Apps from C++ Developers' View
Metro Style Apps from C++ Developers' ViewMetro Style Apps from C++ Developers' View
Metro Style Apps from C++ Developers' ViewEric ShangKuan
 
C++工程实践
C++工程实践C++工程实践
C++工程实践Shuo Chen
 
ajax_onlinemad
ajax_onlinemadajax_onlinemad
ajax_onlinemadKitor23
 
Javascript Training
Javascript TrainingJavascript Training
Javascript Trainingbeijing.josh
 
C++11综述/新特性描述/Overview of C++11 New Features
C++11综述/新特性描述/Overview of C++11 New FeaturesC++11综述/新特性描述/Overview of C++11 New Features
C++11综述/新特性描述/Overview of C++11 New FeaturesPeien Luo
 
Free Marker中文文档
Free Marker中文文档Free Marker中文文档
Free Marker中文文档yiditushe
 
第3章算法与控制语句
第3章算法与控制语句第3章算法与控制语句
第3章算法与控制语句summerfeng
 
Chapter 3 basic syntax and operator
Chapter 3  basic syntax and operatorChapter 3  basic syntax and operator
Chapter 3 basic syntax and operatorhhliu
 
Php extension开发
Php extension开发Php extension开发
Php extension开发thinkinlamp
 
Arduino應用系統設計 - Arduino程式快速入門
Arduino應用系統設計 - Arduino程式快速入門Arduino應用系統設計 - Arduino程式快速入門
Arduino應用系統設計 - Arduino程式快速入門吳錫修 (ShyiShiou Wu)
 
数据处理算法设计要点
数据处理算法设计要点数据处理算法设计要点
数据处理算法设计要点thinkinlamp
 
ES5 introduction
ES5 introductionES5 introduction
ES5 introductionotakustay
 
PHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming SkillsPHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming SkillsHo Kim
 
Python 入门
Python 入门Python 入门
Python 入门kuco945
 
twMVC#27 | C# 7.0 新功能介紹
twMVC#27 | C# 7.0 新功能介紹twMVC#27 | C# 7.0 新功能介紹
twMVC#27 | C# 7.0 新功能介紹twMVC
 

Similar to 認識 C++11 新標準及使用 AMP 函式庫作平行運算 (20)

Go语言: 互联网时代的C
Go语言: 互联网时代的CGo语言: 互联网时代的C
Go语言: 互联网时代的C
 
Metro Style Apps from C++ Developers' View
Metro Style Apps from C++ Developers' ViewMetro Style Apps from C++ Developers' View
Metro Style Apps from C++ Developers' View
 
C++工程实践
C++工程实践C++工程实践
C++工程实践
 
ajax_onlinemad
ajax_onlinemadajax_onlinemad
ajax_onlinemad
 
Javascript Training
Javascript TrainingJavascript Training
Javascript Training
 
C++11综述/新特性描述/Overview of C++11 New Features
C++11综述/新特性描述/Overview of C++11 New FeaturesC++11综述/新特性描述/Overview of C++11 New Features
C++11综述/新特性描述/Overview of C++11 New Features
 
Free Marker中文文档
Free Marker中文文档Free Marker中文文档
Free Marker中文文档
 
第3章算法与控制语句
第3章算法与控制语句第3章算法与控制语句
第3章算法与控制语句
 
Chapter 3 basic syntax and operator
Chapter 3  basic syntax and operatorChapter 3  basic syntax and operator
Chapter 3 basic syntax and operator
 
Php extension开发
Php extension开发Php extension开发
Php extension开发
 
Ch10
Ch10Ch10
Ch10
 
Ch10 教學
Ch10 教學Ch10 教學
Ch10 教學
 
Arduino應用系統設計 - Arduino程式快速入門
Arduino應用系統設計 - Arduino程式快速入門Arduino應用系統設計 - Arduino程式快速入門
Arduino應用系統設計 - Arduino程式快速入門
 
Ch6 函式
Ch6 函式Ch6 函式
Ch6 函式
 
数据处理算法设计要点
数据处理算法设计要点数据处理算法设计要点
数据处理算法设计要点
 
ES5 introduction
ES5 introductionES5 introduction
ES5 introduction
 
PHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming SkillsPHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming Skills
 
Python 入门
Python 入门Python 入门
Python 入门
 
系統程式 -- 第 8 章
系統程式 -- 第 8 章系統程式 -- 第 8 章
系統程式 -- 第 8 章
 
twMVC#27 | C# 7.0 新功能介紹
twMVC#27 | C# 7.0 新功能介紹twMVC#27 | C# 7.0 新功能介紹
twMVC#27 | C# 7.0 新功能介紹
 

認識 C++11 新標準及使用 AMP 函式庫作平行運算

  • 1. Dev306 認識 C++11 新標準 及使用 AMP 函式庫 作平行運算 王建興 qing.chwang at gmail.com
  • 2. 講者簡介 現職 聖藍科技技術長 興趣 網路應用系統開發 譯作 Thinking in Java 4th Edition, 正體中文版 Thinking in Java 2nd Edition, 正體中文版 Essential C++, 正體中文版 專欄 iTHome 電腦報程式人專欄 連絡方式:qing at gmail.com
  • 3. Agenda C++新標準 - C++11 使用C++ AMP做平行運算
  • 5. C++11 C++11,先前被稱作C++0x,即ISO/IEC 14882:2011 C++11,是目前的C++程式語言的正式標準 取代第二版標準ISO/IEC 14882:2003 在2011年八月正式成為標準,故名為C++11
  • 6. C++11要達成的目標 讓C++成為在系統程式設計以及程式庫設計 領域中較好的程式語言 直接使用C++而非為特定應用領域提供專門的開 發語言 使C++更易於教導及學習 增加一致性、加強安全性、為初學者提供相關的 機制 如何達成 在維持效能甚至提升效能的同時,提供更高階、 更抽象化 *http://www.stroustrup.com/C++11FAQ.html#aims
  • 7. C++ 11中的增進 – Core Language 執行時期的效能增進,例如: rvalue reference 對POD定義的修改 建構時期的效能增進,例如: extern template 使用性的加強,例如: 型別的推論 Range-based for-loop 功能的改進,例如 static assertion
  • 8. C++ 11 -從 VC10 到 VC11 (1/3)
  • 9. C++ 11 -從 VC10 到 VC11 (2/3)
  • 10. C++ 11 -從 VC10 到 VC11 (3/3)
  • 11. Concurrency – 從 VC10 到 VC11
  • 12. 今天要談的 C++11 特色 (1/2) Right angle brackets extern template enum Class POD定義的修改 區域及不具名的型別做為模版的參數 Range-for述句
  • 13. 今天要談的 C++11 特色 (2/2) auto Keyword decltype Type Specifier Lambda Expressions rvalue references static_assert nullptr
  • 14. Right Angle Brackets list<vector<string>> lvs; 在C++98中,這是語法錯誤的寫法 編譯器會將 >> 認為是運算子 >> 新編譯器將能理解此種語法
  • 15. extern template 避免多重實例化模版,明確指定模版於它處 實例化 編譯器毋需重複實例化,待鏈結時期再尋找 實例化後的程式碼即可 #include "MyVector.h" extern template class MyVector<int>; // Suppresses implicit instantiation below -- // MyVector<int> will be explicitly instantiated elsewhere void foo(MyVector<int>& v) { // use the vector in here } ------------------------------------------- #include "MyVector.h" template class MyVector<int>; // Make MyVector available to clients (e.g., of the shared library *http://www.stroustrup.com/C++11FAQ.html#extern-templates *http://zevoid.blogspot.tw/2012/04/c11-extern-template.html
  • 16. 傳統C++在enum上的問題 傳統的enum在轉型時會被自動視為int,不 符合此規則時則會引發錯誤 傳統的enum其列舉值在其外圍的程式碼範 圍內皆為可見,這易於產生名稱上的衝突 無法指定enum的底層型別,容易造成誤解 以及相容性的問題 無法進行先行宣告 http://www.stroustrup.com/C++11FAQ.html#enum
  • 17. enum class(更高階的enum) Scoped and Strongly typed enums VC10中並未支援,VC11已支援 enum Alert { green, yellow, election, red }; enum class Color { red, blue }; enum class TrafficLight { red, yellow, green }; Alert a = 7; Color c = 7; int a2 = red; int a3 = Alert::red; int a4 = blue; int a5 = Color::blue; Color a6 = Color::blue; Error Error in C++98; OK in C++11
  • 18. 指定enum的底層型別 並同時決定enum的佔用空間 在過去,佔用空間取決於實作而定 底層型別必須是整數型的型別,預設為int enum class Color : char { red, blue }; enum class TrafficLight { red, yellow, green }; enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U }; // how big is an E? enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U };
  • 19. enum的先行宣告 C++11中可以做先行宣告了 enum class Color_code : char; void foobar(Color_code* p); // ... enum class Color_code : char { red, yellow, green, blue };
  • 20. enum Class的意義 讓列舉型別的表示方式更高階、更抽象、更 直覺 即使是C++的後繼者Java,一開始也沒有專 門的enum type,而是在J2SE 5.0之後加入
  • 21. 對POD定義的修改 POD(Plain Old Data) 符合這種定義的型別能夠允許產生與C相容 的物件佈局 在C++98,POD指的是像C中struct那樣的資 料 能使用memcpy() 能使用memset()進行初始化 struct S { int a; }; // S is a POD struct SS { int a; SS(int aa) : a(aa) { } }; // SS is not a POD struct SSS { virtual void f(); /* ... */ };
  • 22. C++11中的POD struct S { int a; }; // S is a POD struct SS { int a; SS(int aa) : a(aa) { } }; // SS is a POD struct SSS { virtual void f(); /* ... */ }; 在C++11中,SS也是個POD 建構式並不影響 SSS 不會是POD,因為會有個虛擬函式表 C++定義POD是可複製的型別、極簡型別、 以及具有標準佈局的型別 VC10中並未支援,VC11已支援
  • 23. 極簡(trivial)型別或結構 極簡的預設建構式。這可以使用預設建構式 語法 例如SomeConstructor() = default; 極簡的複製建構式,可使用預設語法 極簡的賦值運算子,可使用預設語法 極簡的解構式,不可以是虛擬的 *http://zh.wikipedia.org/zh-tw/C%2B%2B11
  • 24. 標準佈局(standard-layout)的型別或結構 只有非靜態的資料成員,且這些成員也是符 合標準佈局的型別 對所有非靜態成員有相同的存取控制 沒有虛擬函式,也沒有虛擬基礎類別 只有符合標準佈局的基礎類別 沒有和第一個定義的非靜態成員相同型別的 基礎類別 若非沒有帶有非靜態成員的基礎類別,就是 最底層(繼承最末位)的型別沒有非靜態資料 成員而且至多一個帶有非靜態成員的基礎類 別。基本上,在該型別的繼承體系中只會有 一個型別帶有非靜態成員
  • 26. 區域及不具名的型別做為模版的參數 在C++98,區域及不具名的型別不能做為模 版的參數傳入 如今,在C++11中支援了 一致性更好 void f(vector<X>& v) { struct Less { bool operator()(const X& a, const X& b) { return a.v<b.v; } }; sort(v.begin(), v.end(), Less()); // C++98: error: Less is local // C++11: ok } *http://www.stroustrup.com/C++11FAQ.html#local-types
  • 27. 不具名型別的值也能做為模版參數 template<typename T> void foo(T const& t){} enum X { x }; enum { y }; int main() { foo(x); // C++98: ok; C++11: ok foo(y); // C++98: error; C++11: ok enum Z { z }; foo(z); // C++98: error; C++11: ok }
  • 28. auto Keyword (1/3) auto 關鍵字能從所宣告變數的初始算式,導 出其型別 ( 當然是編譯時期 ) auto declarator initializer; int j = 0; auto k = 0; // Variable k is implicitly type int *http://msdn.microsoft.com/en-us/library/dd293667(v=VS.100).aspx
  • 29. auto Keyword (2/3) map<int,list<string>>::iterator i = m.begin(); auto i = m.begin(); auto x = 1, *y = &x, **z = &y; // Resolves to int. auto a(2.01), *b (&a); // Resolves to double. auto c = 'a', *d(&c); // Resolves to char. auto m = 1, &n = m; // Resolves to int.
  • 30. auto Keyword (3/3) 使用 auto 關鍵字時的重要限制 使用時一定要搭配 initializer 不能用來宣告陣列、變數的 return type、函 式或 template 的參數 除了 static member 之外,不能在 class/struct 中使用 auto 宣告 data member
  • 31. 錯誤的 auto 使用 auto a; auto ary[10]; auto ary2[] = { 1, 2, 3} auto foo(); void bar(auto a); struct A { auto a; };
  • 32. 使用 auto 的時機 當資料型別可能隨著編譯器或目標平台而異 時 例 strlen() 的回傳型別 當資料型別過於複雜不易表示時 例 map<int,list<string>>::iterator i 將 Lambdas 指派至變數時 ( 待續, Lambdas 算式 ) 指定 Trailing Return Types ( 待續, decltype )
  • 33. auto vs. auto /Zc:auto[-] 編譯器選項是用來告訴編譯器看 待宣告變數時 auto 這個關鍵字的確切意義 指定 /Zc:auto 編譯器會從所宣告變數的初始 算式推導出其確型別 指定 /Zc:auto- 編譯器會以 automatic storage class 來宣告變數 此為相容性問題 *http://msdn.microsoft.com/en-us/library/dd293615.aspx
  • 34. decltype Type Specifier (1/2) decltype 是個 type specifier decltype 依據所給定的算式來決定型別 decltype( expression ) decltype 不同於 typeid,因為它是從算式中 得到型別本身,而非型別資訊
  • 35. decltype Type Specifier (2/2) int var; const int&& fx(); struct A { double x; } const A* a = new A(); decltype(fx()); // const int && decltype(var) // int decltype(a->x) // double ( The type of the member access ) decltype((a->x)) // const double && (an expression instead of a member access )
  • 36. 使用 decltype 的時機 適當的表示資料型別 decltype(mstr.begin()->second.get_allocator()) under_alloc; decltype 和 auto 不同的是,auto 推導型別 是靠初始算式,得發生指派動作 decltype 只是從算式評估結果的型別來推導 型別,但卻不會確切的進行評估 decltype(mstr.begin()->second.get_allocator()) under_alloc;
  • 37. trailing-return-type auto function_name( parameters ) −> decltype( expression ) { function_body; } template<typename T, typename U> auto myFunc( T& t, U& u)-> decltype( t + u ){ return t + u; };
  • 38. C++11對型別推論的加強 auto及decltype 其作用皆是在編譯時期推論 型別 編譯器在編譯時期確切的能從變數的初始化 述句以及算式得到最終該有的型別 編譯時期的動作不影響執行時期的效能 C++的一貫哲學 之所以要有型別推論不是因為那些顯而易見 的型別宣告問題 長久以來C++程式設計者受模版庫中複雜的型別 宣告所苦 它們確切究竟是什麼型別並不那麼重要
  • 39. Ranged-for 透過Ranged-for 述句,可以在迴圈裡遞代一 組元素 所有標準的容器、 std::string 、初始化列表 、陣列、以及所有可以定義begin()及end()的 類別都可適用 void f(vector<double>& v) { for (auto x : v) cout << x << 'n'; for (auto& x : v) ++x; } for (const auto x : { 1,2,3,5,8,13,21,34 }) cout << x << 'n'; *http://www.stroustrup.com/C++11FAQ.html#aims
  • 40. Ranged-for 的意義 提供更高階的迴圈語義 Compiler Sugar 即使如Java,也在J2SE 5.0之後,加入了 forech的語法
  • 41. Lambda Expressions(1/4) 基本上就像是個匿名函式(anonymous function) []() mutable throw() -> typeid { //function body } Lambda Expression 使得函式可以在使用的 地方定義,並且可以在Lambda 函式中使用 Lambda 函式之外的變數 比函式物件或函式指標方便且單純
  • 42. Lambda Expressions(2/4) 1.capture clause 2.parameter list 3.mutable specification 4.exception specification 5.return type 6.lambda body
  • 43. Lambda Expressions (3/4) capture clause *http://heresy.spaces.live.com/blog/cns!E0070FB8ECF9015F!10575.entry
  • 44. Lambda Expressions (4/4) parameter list 不能有預設引數 不能有可變長度引數列表 不能有不具名參數 沒有參數時,可省略 parameter list int main() { int x = 4; int y = 5; int z = [=] { return x + y; } ; }
  • 45. 使用函式物件 struct FunctionObj { void operator()(int n) const { // 對n操作 } } … for_each(v.begin(), v.end(), FunctionObj ());
  • 47. rvalue references rvalue reference 被創造,其中最大的意義 之一,便是為了提供更有效率的 move 語義 rvalue reference 語法 type-id && cast-expression *http://msdn.microsoft.com/en-us/library/dd293668(v=VS.100).aspx
  • 48. lvalue & rvalue (1/2) 每個算式,若非 lvalue 便為 rvalue lvalue 指的是在單一算式之後所代表的一個 續存物件 例:++x rvalue 指的是在算式評估結束之後,生命期 便結束的暫時性物件 例:x++ 能對它取址的即為 lvalue *http://blogs.msdn.com/b/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx
  • 49. lvalue & rvalue (2/2) string one("cute"); const string two("fluffy"); string three() { return "kittens"; } const string four() { return "are an essential part of a healthy diet"; } one; // modifiable lvalue two; // const lvalue three(); // modifiable rvalue four(); // const rvalue
  • 50. C++ 的複製問題 每次 + 運算子執行時,都會產生一個暫時性 物件 string s0("my mother told me that"); string s1("cute"); string s2("fluffy"); string s3("kittens"); string s4("are an essential part of a healthy diet"); string dest = s0 + " " + s1 + " " + s2 + " " + s3 + " " + s4; 產生了八個暫時性物件!
  • 51. 問題出在那裡? 因為 s0 是個 lvalue 不能加以修改,所以在 計算 s0 + “ “ 時,得建立一暫時物件 但在接著計算 (s0 + “ ”) + s1 時,可以直接 把 s1 接到之前建立的暫時物件後,便毋需 再產生第二個暫時物件,並捨棄第一個暫時 物件 這便是 move 語義的核心觀念
  • 52. move 語義的實作 (1/2) 在 C++11 中,每次 + 運算子被呼叫時,仌 會產生獨立的暫時物件 但第二次呼叫 + 運算子時(例如在((s0 + “ ”) + s1)中),會將前一個暫時物件所配置 的記憶體挪過來使用 只更動第二個暫時物件指標之值,而不重新 配置並複製 第一個暫時物件的指標則指向 null,避免解 構時的相關行為
  • 53. move 語義的實作 (2/2) 所以,若能偵測到處理的是 non-const rvalue 時,就可以直接挪用其記憶體 反正它很快就要被摧毀,又沒人在乎它 從 rvalue 建立物件,或指派 rvalue 物件之 值至另一物件時,所謂的 moving,便是挪 用其記憶體的動作 例如 vector 要擴展空間時,moving 就很重 要 那問題就是在於要如何偵測了!
  • 54. rvalue reference C++11 引入了名為 rvalue reference 的新 reference,其語法為 Type&& 及 const Type&& rvalue reference 與 lvalue reference 是不同 的型別 但在語意上都一樣是 reference
  • 55. 兩種 reference 在函式重載時的不同行為 Type& 只能繫結到 non-const lvalue const Type& 可以繫結到任何東西 Type&& 可以繫結到 non-const lvalue 及 non-const rvalue const Type&& 可以繫結到任何東西
  • 56. rvalue reference 的overload resolution void purr(const string& s) { cout << "purr(const string&): " << s << endl; } void purr(string&& s) { cout << "purr(string&&): " << s << endl; } string strange() { return "strange()"; } const string charm() { return "charm()"; } int main() { string up("up"); const string down("down"); purr(up); // purr(const string&): up purr(down); // purr(const string&): down purr(strange()); // purr(string&&): strange() purr(charm()); // purr(const string&): charm() }
  • 57. 提供 move 語義 傳統的 copy 建構子 Simple(const Simple&); C++0x 中的 move 建構子 Simple(Simple&&); 編譯器並不會提供預設的 move 建構子 *範例取自 http://www.codeproject.com/KB/cpp/cpp10.aspx#RValues
  • 58. move 建構子被呼叫 Simple GetSimple() { Simple sObj(10); return sObj; }
  • 59. 實作 move 建構子(1/2) class Simple { // The resource void* Memory; public: Simple() { Memory = nullptr; } // The MOVE-CONSTRUCTOR Simple(Simple&& sObj) { // Take ownership Memory = sObj.Memory; // Detach ownership sObj.Memory = nullptr; } };
  • 60. 實作 move 建構子(2/2) Simple(int nBytes) { Memory = new char[nBytes]; } ~Simple() { if(Memory != nullptr) delete []Memory; } };
  • 61. move 指派運算子 傳統的 copy 指派運算子 void operator=(const Simple&); C++0x 中的 move 指派運算子 void operator=(Simple&&);
  • 62. 實作 move 指派運算子 class Simple { ... void operator = (Simple&& sOther) { // De-allocate current delete[] Memory; // Take other's memory contnent Memory = sOther.Memory; // Since we have taken the temporary's resource. // Detach it! sOther.Memory = nullptr; } };};
  • 63. rvalue reference的引入 減尐了一些執行時期額外的記憶體配置以及 重覆複製資料的負擔 對提升運行效能有所幫助 尤其對程式庫中的類別而言
  • 64. static_assert Declaration (1/2) 在編譯時期針對指定條件檢驗是否成立 static_assert( constant-expression, string-literal ); constant-expression: 若值評估為 0,則編譯 失敗並顯示string-literal參數之值,反之,則 無任何影響
  • 65. static_assert Declaration (2/2) 應用: static_assert( sizeof(void *)==4, "64-bit code generation is not supported.");
  • 66. static_assert 與傳統方式的比較 在過去有兩種檢查方式 條件編譯 + #error 指令 ( 在 preprocessing 階段 ) assert 巨集 ( 在 runtime ) #error 無法針對 template 參數進行檢查,因 為 class 是在編譯時才會被 instantiated static_assert 是在編譯時期進行檢查,所以 可以處理 template 參數的檢查
  • 67. nullptr Keyword nullptr 關鍵字用來表示指向空值的指標 解決 0 和指向空值指標的混淆情況 提供更直觀更不易出錯的空指標表示方式 void f(int){ printf( "intn" ); } void f(char*){ printf( "char*n" ); } f( NULL ); // int, compile error in GCC f( 0 ); // int f( (char*)0 ); // char* f( (void*)0 ); // compile error *http://heresy.spaces.live.com/blog/cns!E0070FB8ECF9015F!10891.entry
  • 68. 概括C++11的加強方向 增加編譯、鏈結時的效能 增加實際執行的效能 提供更高階、更抽象的程式設計方式 提供更簡便、更不易出錯的程式設計方式
  • 70. 何謂 C++ AMP? AMP: Accelerated Massive Parallelism 在一個或多個的加速器上執行計算 目前,實際的加速器就是GPU 未來,會有其他型式的加速器 有了C++ AMP後,可以完全使用C++撰寫應 用程式來獲得平行計算的加速 可加速數十倍或更多 AMP 基本上是個程式庫 附於Visual Studio 2012中 規格開放,其他平台或編譯器亦可實作
  • 71. C++ AMP的設計原則 基於C++而非C 能成為主流 愈簡化的程式設計模型愈好 盡可能尐的改動 具可攜性 可於任何廠商的硬體上執行 通用且不會過期 使用不同的加速器,例如雲端上的加速器 開放 規格開放
  • 72. CPU vs. GPU 較低的記憶體頻寬 較高的記憶體頻寬 高耗能 低耗能 中度平行化 高度平行化 較深的指令管線 較淺的指令管線 隨機存取 循序存取 支援通用型的程式 支援平行資料操作的程 通用型的程式設計 式 專用型的程式設計
  • 73. GPGPU General-Purpose computing on Graphics Processing Units 也稱GP²U 傳統的GPU通常是處理和圖形有關的計算 由於現代GPU具有強大的並行處理能力,使 得GPU也可以用來處理一些通用類型的資料 尤其是面對單一指令多資料流(SIMD)的情況 目前, OpenCL是現存的GPGPU計算語言 Nvidia的CUDA則是現成的封閉式框架
  • 74. 異質性計算(Heterogeneous Computing) 在同一計算系統中,使用不同指令集和架構 的計算單元來組成計算方式,即為異質性計 算 常見的計算單元包括像是 CPU, GPU, DSP, ASIC, FPGA … 等等 不同類型計算單元的長處各不盡相同 異質性計算則嘗試綜合各自的長處 例如GPU擅長平行計算 組合CPU+GPU計算的系統,即屬異質性計 算系統
  • 75. GPU所能容納的執行緒數-例 NVIDIA GTX 690 16個多處理器 每個多處理器有192個CUDA核心 每個多處理器的最大執行緒數是2048 可同時容納最多32,768個執行緒 NVIDIA GTX 560 SE 9個多處理器 每個多處理器有32個CUDA核心 每個多處理器的最大執行緒是1536 可以同時容納最多13,824個執行緒 *http://www.infoq.com/cn/articles/cpp_amp_computing_on_GPU
  • 76. 程式庫型式的C++ AMP (1/2) 附於Visual Studio 2012之中 是個STL-like的程式庫 #include <amp.h>後取用 Namespace: concurrency 新類別 array, array_new extent, index accelerator, accelerator_new
  • 77. 程式庫型式的C++ AMP (2/2) 新函式 parallel_for_each() 新關鍵字(或說同名但新的用法) restrict 用來告訴編譯器檢查GPU(DirectX)
  • 78. parallel_for_each 程式庫的入口 接收參數 所需的執行緒數 在每個執行緒中執行的函式或labmda(必須是 restrict(amp)) 將工作送至加速器 返回 – 不會有遲滯或等待
  • 79. Hello AMP: 陣列相加 #include <amp.h> using namespace concurrency; void AddArrays(int n, int * pA, int * void AddArrays(int n, int * pA, int * pB, int * pSum) pB, int * pSum) { { array_view<int,1> a(n, pA); array_view<int,1> b(n, pB); array_view<int,1> sum(n, pSum); for (int i=0; i<n; i++) parallel_for_each( sum.extent, [=](index<1> i) restrict(amp) { { pSum[i] = pA[i] + pB[i]; sum[i] = a[i] + b[i]; } } ); } }
  • 80. C++ AMP程式設計的基本元素 void AddArrays(int n, int * pA, int * pB, int * pSum) array_view { 將資料包裝成可於 array_view<int,1> a(n, pA); 加速器上操作的型 array_view<int,1> b(n, pB); 式 array_view<int,1> sum(n, pSum); parallel_for_each 在每個執行緒上執 parallel_for_each( 行一次函式或 lambda sum.extent, [=](index<1> i) restrict(amp) extent { 執行lambda的執行 緒個數及結構形狀 sum[i] = a[i] + b[i]; } index ); 執行labmda的執行 緒ID,做為資料的 } 索引 操作 restrict(amp) 表示amp限制
  • 83. array_view<T, N> vector<int> v(10); 檢視CPU或GPU 上既存的資料 extent<2> e(2,5); 元素型別T,並有 array_view<int,2> a(e, v); N維 需指定extent 矩形 //above two lines can also be written 隨處可存取(自動 //array_view<int,2> a(2,5,v); 同步) index<2> i(1,3); int o = a[i]; // or a[i] = 16; //or int o = a(1, 3);
  • 84. restrict(amp)的限制 僅能呼叫其他同為restrict(amp)的函式 所有的函式都必須是可inline 僅能使用支援amp的型別 int, unsigned int, float, double, bool 上述型別構成的struct 及陣列 指標及參照的限制 Lambda不能是capture by reference或是 capture pointer 參照及單向指標僅能做為區域變數及函式的引數
  • 86. array<T, N> vector<int> v(8 * 12); extent<2> e(8,12); 多維陣列,元素型別T, accelerator acc = … N維 array<int,2> a(e,acc.default_view); 存於特定加速器中的儲存 copy_async(v.begin(), v.end(), a); 空間 Capture by reference 自行指定的複製動作 parallel_for_each(e, [&](index<2> idx) 和array_view<T, N>相近 restrict(amp) 的介面 { a[idx] += 1; }); copy(a, v.begin());
  • 87. parallel_for_each的非同步特性 呼叫完立即返回 當嘗試透過array_view存取處理中的資料時 ,若尚未運行完畢,則會等待,直到運算結 束為止 可運用array_view的synchronize_async()函 式來處理計算的完成事件 std::shared_future<void> synchronize_async() const;
  • 88. 撰寫C++ AMP程式簡單直覺 撰寫C++ AMP程式的步驟 建立arr​​ay_view物件 呼叫parallel_for_each 利用array_view物件得到計算結果 CPU和GPU之間的溝通細節,皆由程式庫包 裝 記憶體的分配和釋放 資料的同步 GPU執行緒的規劃和管理
  • 89. Visual Studio 2012對C++ AMP的除錯支援 中斷點 偵錯類型 變數值及call stack的察看 GPU的執行緒狀態 平行計算資料的察看
  • 90. 中斷點的設定 可停在CPU或GPU的中斷點 GPU的中斷點僅Windows 8支援 *Kate Gregory, “C++ Accelerated Massive Parallelism in Visual C++ 2012”
  • 95. 開發/執行C++ AMP的條件 開發 Visual Studio 2012 支援DirectX 11的顯示卡 Windows 8作業系統 執行 Windows 7/Windows 8 支援DirectX 11的顯示卡
  • 96. 看待C++ AMP程式的效能問題 愈包裝的夠高階夠抽象的程式庫愈有提升效 能的可能性 基於C++ AMP的程式本身結構夠簡單 效能取決於C++ AMP程式庫的實作 當然還有底層的硬體條件 只要程式庫被專家最佳化了,應用程式就變 快了
  • 97. http://www.microsoft.com/taiwan/techdays2012/ http://www.microsoft.com/learning/zh/tw/ http://social.technet.microsoft.com/Forums/zh- http://social.msdn.microsoft.com/Forums/zh- tw/categories/ tw/categories/