2018年12月27日 星期四

Concurrency and asynchronous operations with C++/WinRT

簡單紀錄一下Concurrency and asynchronous operations with C++/WinRT

The Windows::Foundation Windows Runtime namespace contains four types of asynchronous operation object.
- IAsyncAction,
- IAsyncActionWithProgress,
- IAsyncOperation, and
- IAsyncOperationWithProgress.

在使用asynchronous Windows function時有2種方式
- blocking
- non-blocking
blocking適合用在console program或是background thread,不適合用在UI thread.


*********************************
coroutine介紹
*********************************
C++/WinRT 整合了 C++ coroutines into the programming model to provide a natural way to cooperatively wait for a result.
只要在function前宣告成上述提到的4種asynchronous operation object,即為coroutines。如下ProcessFeedAsync

IAsyncAction ProcessFeedAsync()
{
    Uri rssFeedUri{ L"https://blogs.windows.com/feed" };
    SyndicationClient syndicationClient;
    SyndicationFeed syndicationFeed{ co_await syndicationClient.RetrieveFeedAsync(rssFeedUri) };
    print_function();
}

下例即為如何呼叫此coroutine:
int main
{
    auto processOp{ ProcessFeedAsync() };
    processOp.get();
}

MS對coroutine的解釋:
A coroutine is a function that can be suspended and resumed. In the ProcessFeedAsync coroutine above, when the co_await statement is reached, the coroutine asynchronously initiates the RetrieveFeedAsync call and then it immediately suspends itself and returns control back to the caller (which is main in the example above). main can then continue to do work while the feed is being retrieved and printed. When that's done (when the RetrieveFeedAsync call completes), the ProcessFeedAsync coroutine resumes at the next statement.


*********************************
coroutine回傳值
*********************************
coroutine可以回傳Windows Runtime type,如上。也可以回傳非Windows Runtime type,如concurrency::task. 範例如下
concurrency::task RetrieveFirstTitleAsync()
{
    return concurrency::create_task([]
    {
        Uri rssFeedUri{ L"https://blogs.windows.com/feed" };
        SyndicationClient syndicationClient;
        SyndicationFeed syndicationFeed{ syndicationClient.RetrieveFeedAsync(rssFeedUri).get() };
        return std::wstring{ syndicationFeed.Items().GetAt(0).Title().Text() };
    });
}

int main()
{
    winrt::init_apartment();

    auto firstTitleOp{ RetrieveFirstTitleAsync() };
    // Do other work here.
    std::wcout << firstTitleOp.get() << std::endl;
}


*********************************
coroutine參數
*********************************
如果需要在coroutine中傳遞參數,要用const,以確保thread safe.


*********************************
coroutine的thread
*********************************
coroutine在碰到co_await, co_return, or co_yield時會rutern。
但如果在coroutine裡面沒有機會使用到這幾個時,可以直接使用
co_await winrt::resume_background();
這樣可以讓自己被丟到system thread pool,返回caller的thread,然後讓system啟動一個thread來完成自己的coroutine.

然而使用co_await winrt::resume_foreground(UI_thread)可以讓自己的thread回到UI thread,這個方式可以用來update UI.

值得注意的是在suspension點之後,原來的thread可能會消失不見,resume之後可能會是另一條thread來執行。但是如果我們使用的是Windows Runtime type (IAsyncXXX)的話,C++/WinRT會自動幫我們處理。C++/WinRT會在suspension之前先紀錄calling context,等到resume時會檢查並確保是在calling context. 如果不是使用(IAsyncXXX)的話,請記得確認此library有提供這個技術。


*********************************
Canceling an asychronous operation, and cancellation callbacks
*********************************
使用 IAsyncXXX.Cancel()來取消一個async operation.
或用 IAsyncXXX.callback()來註冊取消一個async operation之後要執行的function.

*********************************
Reporting progress
*********************************
使用 IAsyncActionWithProgress或IAsyncOperationWithProgress來回報進度。

*********************************
Fire and forget
*********************************
宣告coroutine為winrt::fire_and_forget,即為不等待結束。

The visual studio behavior with WinRT runtime component

When "windows runtime component" project created with winrt type.
1. VS default create Class.idl, Class.h, Class.cpp under root of project folder.
2. when project built, VS will generate some files in "Generated Files" folder.
    - Class.g.h
    - module.g.cpp
    - folder "winrt"
        - $project_name.h          // define template for Class
        - folder "impl"
            - $project_name.0.h    // define template for $project_name.1.h
            - $project_name.1.h    // define IClass for $project_name.2.h
            - $project_name.2.h    // define Class for $project_name.h
        - folder "source"
            - Class.h              // this file content is same as default created Class.h
            - Class.cpp            // this file content is same as default created Class.cpp

3. When change members in Class.idl and rebuild project.
3.1. files under root project folder.
    - Class.h                      // not re-generated.
    - Class.cpp                    // not re-generated.
3.2. files under "Generated Files" folder.
    - Class.g.h                    // re-generated, not content is not affected.
    - module.g.cpp                 // re-generated, not content is not affected.
    - files under "Generated Files/winrt" folder.
        - $project_name.h          // re-generated, add members.
        - files under "Generated Files/winrt/impl" folder.
            - $project_name.0.h    // re-generated, add members.
            - $project_name.1.h    // re-generated, not content is not affected.
            - $project_name.2.h    // re-generated, not content is not affected.
        - files under "Generated Files/winrt/source" folder.
            - Class.h              // re-generated, add members.
            - Class.cpp            // re-generated, add members.

4. When rename class name in Class.idl
4.1. files under root project folder.
    - Class.h                      // not re-generated.
    - Class.cpp                    // not re-generated.
4.2. files under "Generated Files" folder.
    - Class.g.h                    // not re-generated. just because new class file generated.
    - NewClass.g.h                 // new class file generated.
    - module.g.cpp                 // re-generated, content changed.
    - files under "Generated Files/winrt" folder.
        - $project_name.h          // re-generated, content changed to new class related.
        - files under "Generated Files/winrt/impl" folder.
            - $project_name.0.h    // re-generated, content changed to new class related.
            - $project_name.1.h    // re-generated, content changed to new class related.
            - $project_name.2.h    // re-generated, content changed to new class related.
        - files under "Generated Files/winrt/source" folder.
            - Class.h              // not re-generated. just because new class file generated.
            - Class.cpp            // not re-generated. just because new class file generated.
            - NewClass.h           // new class file generated.
            - NewClass.cpp         // new class file generated.

           
           
           
           
           
           
           
           
           
           
           
           
           
           
           
           
           
           
           

2018年10月11日 星期四

amazon echo's skills

最近在研究如何開發amazon echo的程式,也就是如何讓擁有amazon echo裝置的人可以有更多話語跟echo裝置互動。

在amazon echo的世界裡,有一個虛擬的助手叫alexa,alexa擁有依些基本對話功能,基本對話能力是amazon開發時就已經內建在echo裏面了,但是amazon不希望echo只能做這些事,所以開放一些SDK,讓全世界有興趣的工程師一起來擴張amazon的能力。這個能力在amazon的世界裏面稱做skill。

可以對比成:android的世界裏面,開發者可以開發許多app,在amazon的世界裏面,這些app稱做skill。

不廢話進重點。

當一個開發者想要開發skill時,要先知道skill怎樣分類,amazon將skill分成四大類。
1. Custom skill
2. Smart Home Skill API
3. Video Skill API
4. Flash Briefing Skill API
接下來分別簡單說說這四大類。

Custom skill
這一類就是讓開發者完全自己定義要如何跟使用者互動,如:到某個網站查詢資料,開發互動式遊戲等等。

Smart Home Skill API
這一類可以讓使用者控制IoT裝置,如Smart TV,電燈,門鎖等等。

Video Skill API
這一類skill者要是讓使用者控制雲端的視頻服務,如播放影片,暫停播放,播歌等等。

Flash Briefing Skill API
最後一類是播放簡報,這裡的簡報意指使用者事前已經設定好的資料,如報紙的頭條新聞,讓alexa播報出來。

參考資料:https://developer.amazon.com/docs/ask-overviews/build-skills-with-the-alexa-skills-kit.html

2016年10月11日 星期二

如何解決eclipse無法在ubuntu 16.04上啟動

狀況:
ubuntu升級到16.04版之後,eclipse無法啟動,會一直卡在splash畫面。

解決方式:
問題應該是在16.04裡GTK+ 3的版本。

請先用下面步驟確認:
打開一個terminal視窗,然後輸入
export SWT_GTK3=0
然後在terminal視窗裡下命令啟動Eclipse.
如果這樣可以使得eclipse正常啟動。那請在eclipse.ini中加入下列2行敘述。

--launcher.GTK_version
2

請加在 --launcher.appendVmargs 前面。

相關的bug
Ubuntu bug 1552764

2016年5月30日 星期一

密碼學

最近在學習AllJoyn security 2.0,裏面有一些密碼學的東西,也順便一起看一下,有幾個不錯的概念網站,順便紀錄下來。


PK(金鑰加密系 統,Public Key Cryptosystems)的作用包括「資料保密」和「身份認證」兩方面。

當你需要寄送加密檔案給某人(假設為A君)時,需先向PK伺服器查詢A君的公 開金鑰,再以取得的公開金鑰進行資料加密。由於檔案是用A君的公開金鑰加密的,因此只有A君的私密金鑰才能解密。只要A君妥善保管好自己的私密金鑰,就能 確保檔案的隱密性。

至於身份確認方面,你需要事先透過適當的安全管道把代表自己身份的電子簽章檔送給A君,電子簽章檔可以是文字檔或簽名、印章的影像檔。 當你把利用A君公開金鑰加密的資料檔Email給對方時,可以附加上利用自己私密金鑰加密的電子簽章檔。

A君收到你寄送去的資料檔和電子簽章檔之後,可以使用他自己的私密金鑰對資料檔解密,同時向PK伺服器查詢你的公開金鑰,再利用取得的公開金鑰對電子簽章檔解密
比對解密後的電子簽章檔和你事先交付的電子簽章檔無誤之後,A君就能確認資料檔確實是你寄送給他的。

PK登記手續只需辦理一次,之後就可以透過網路隨時更換寄存在PK伺服器裡的 公開金鑰。使用者只要勤於更換公開金鑰和私密金鑰,甚至每一對公開金鑰和私密金鑰只用一次,用過即換,即可保障通訊內容安全無虞。


參考書目
Live-CA:結合 IC 卡的 PKI 憑證管理系統之設計與實現--國立高雄師範大學資訊教育研究所碩士論文

稻江科技暨管理學院提供的教學:密碼學原理與技術

Ivan Blog:何謂PKI?



2016年4月28日 星期四

[轉貼]用gcc 自製 Library

轉自 PTT LinuxDev


作者: cole945 (躂躂..) 看板: LinuxDev
標題: [心得] 用gcc 自製Library
時間: Sun Nov 5 04:15:45 2006


Library可分成三種,static、shared與dynamically loaded。


1. Static libraries
Static 程式庫用於靜態連結,簡單講是把一堆object檔用ar(archiver)包裝集合起來,檔名以`.a’ 結尾。優點是執行效能通常會比後兩者快,而且因為是靜態連結,所以不易發生執行時找不到library或版本錯置而無法執行的問題。缺點則是檔案較大,維護度較低;例如library如果發
現bug需要更新,那麼就必須重新連結執行檔。

1.1 編譯
編譯方式很簡單,先例用`-c’ 編出object 檔,再用ar 包起來即可。

____ hello.c ____
#include
void hello(){ printf(“Hello “); }

____ world.c ____
#include

void world(){ printf(“world.”); }

____ mylib.h ____
void hello();
void world();


$ gcc -c hello.c world.c /* 編出hello.o 與world.o */

$ ar rcs libmylib.a hello.o world.o /* 包成limylib.a */


這樣就可以建出一個檔名為libmylib.a 的檔。輸出的檔名其實沒有硬性規定,但如果想要配合gcc 的’-l’ 參數來連結,一定要以`lib’ 開頭,中間是你要的library名稱,然後緊接著`.a’ 結尾。


1.2 使用

____ main.c ____
#include “mylib.h”
int main() {
    hello();
    world();
}


使用上就像與一般的object 檔連結沒有差別。

$ gcc main.c libmylib.a

也可以配合gcc 的`-l’ 參數使用

$ gcc main.c -L. -lmylib

-L 參數用來指定要搜尋程式庫的目錄,`.’ 表示搜尋現在所在的目錄。通常預設會搜/usr/lib 或/lib 等目錄。
-l 參數用來指定要連結的程式庫,’mylib’ 表示要與mylib進行連結,他會搜尋library名稱前加`lib’後接`.a’的檔案來連結。

$ ./a.out
Hello world.



2. Shared libraries
Shared library 會在程式執行起始時才被自動載入。因為程式庫與執行檔是分離的,所以維護彈性較好。有兩點要注意,shared library是在程式起始時就要被載入,而不是執行中用到才載入,而且在連結階段需要有該程式庫才能進行連結。

首先有一些名詞要弄懂,soname、real name與linker name。

soname 用來表示是一個特定library 的名稱,像是libmylib.so.1 。前面以`lib’ 開頭,接著是該library 的名稱,然後是`.so’ ,接著是版號,用來表名他的介面;如果介面改變時,就會增加版號來維護相容度。
real name 是實際放有library程式的檔案名稱,後面會再加上minor 版號與release 版號,像是libmylib.so.1.0.0 。一般來說,版號的改變規則是(印象中在APress-Difinitive Guide to GCC中有提到,但目前手邊沒這本書),最尾碼的release版號用於程式內容的修正,介面完全沒有改變。中間的minor用於有新增加介面,但相舊介面沒改變,所以與舊版本相容。最前面的version版號用於原介面有移除或改變,與舊版不相容時。
linker name是用於連結時的名稱,是不含版號的soname ,如: libmylib.so。通常linker name與real name是用ln 指到對應的real name ,用來提供彈性與維護性。


2.1 編譯

shared library的製作過程較複雜。

$ gcc -c -fPIC hello.c world.c

編譯時要加上-fPIC 用來產生position-independent code。也可以用-fpic參數。(不太清楚差異,只知道-fPIC 較通用於不同平台,但產生的code較大,而且編譯速度較慢)。

$ gcc -shared -Wl,-soname,libmylib.so.1 -o libmylib.so.1.0.0 hello.o world.o

-shared 表示要編譯成shared library
-Wl 用於參遞參數給linker,因此-soname與libmylib.so.1會被傳給linker處理。
-soname用來指名soname 為limylib.so.1
library會被輸出成libmylib.so.1.0.0 (也就是real name)

若不指定soname 的話,在編譯結連後的執行檔會以連時的library檔名為soname,並載入他。否則是載入soname指定的library檔案。可以利用objdump 來看library 的soname。

$ objdump -p libmylib.so | grep SONAME
SONAME libmylib.so.1

若不指名-soname參數的話,則library不會有這個欄位資料。在編譯後再用ln 來建立soname 與linker name 兩個檔案。

$ ln -s libmylib.so.1.0.0 libmylib.so
$ ln -s libmylib.so.1.0.0 libmylib.so.1

2.2 使用
與使用static library 同。

$ gcc main.c libmylib.so

以上直接指定與libmylib.so 連結。或用

$ gcc main.c -L. -lmylib

linker會搜尋libmylib.so 來進行連結。如果目錄下同時有static與shared library的話,會以shared為主。使用-static 參數可以避免使用shared連結。

$ gcc main.c -static -L. -lmylib

此時可以用ldd 看編譯出的執行檔與shared程式庫的相依性

$ldd a.out

linux-gate.so.1 => (0xffffe000)
libmylib.so.1 => not found
libc.so.6 => /lib/libc.so.6 (0xb7dd6000)
/lib/ld-linux.so.2 (0xb7f07000)

輸出結果顯示出該執行檔需要libmylib.so.1 這個shared library。會顯示not found 因為沒指定該library所在的目錄,所找不到該library。因為編譯時有指定-soname參數為libmylib.so.1 的關係,所以該執行檔會載入libmylib.so.1。否則以libmylib.so連結,執行檔則會變成要求載入libmylib.so

$ ./a.out

./a.out: error while loading shared libraries: libmylib.so.1
cannot open shared object file: No such file or directory

因為找不到libmylib.so.1 所以無法執行程式。有幾個方式可以處理。
a. 把libmylib.so.1 安裝到系統的library目錄,如/usr/lib下
b. 設定/etc/ld.so.conf ,加入一個新的library搜尋目錄,並執行ldconfig更新快取
c. 設定LD_LIBRARY_PATH 環境變數來搜尋library

這個例子是加入目前的目錄來搜尋要載作的library

$ LD_LIBRARY_PATH=. ./a.out
Hello world.


3. Dynamically loaded libraries
Dynamicaaly loaded libraries 才是像windows 所用的DLL ,在使用到時才載入,編譯連結時不需要相關的library。動態載入庫常被用於像plug-ins的應用。

3.1 使用方式
動態載入是透過一套dl function來處理。

#include
void *dlopen(const char *filename, int flag);
開啟載入filename 指定的library。

void *dlsym(void *handle, const char *symbol);
取得symbol 指定的symbol name在library被載入的記憶體位址。

int dlclose(void *handle);
關閉dlopen開啟的handle。

char *dlerror(void);
傳回最近所發生的錯誤訊息。

____ dltest.c ____
#include
#include
#include

int main() {
    void *handle;
    void (*f)();
    char *error;

    /* 開啟之前所撰寫的libmylib.so 程式庫*/
    handle = dlopen(“./libmylib.so”, RTLD_LAZY);
    if( !handle ) {
        fputs( dlerror(), stderr);
    exit(1);
    }

    /* 取得hello function 的address */
    f = dlsym(handle, “hello”);
    if(( error=dlerror())!=NULL) {
        fputs(error, stderr);
        exit(1);
    }
    /* 呼叫該function */
    f();
    dlclose(handle);
}

編譯時要加上-ldl 參數來與dl library 連結

$ gcc dltest.c -ldl

結果會印出Hello 字串

$ ./a.out

Hello

關於dl的詳細內容請參閱man dlopen


參考資料:
Creating a shared and static library with the gnu compiler [gcc]
http://www.adp-gmbh.ch/cpp/gcc/create_lib.html
Program Library HOWTO
http://tldp.org/HOWTO/Program-Library-HOWTO/index.html
APress – Definitive Guide to GCC

2014年10月8日 星期三

在ubuntu上,如何設定開機自動執行一些script

1. 針對個別使用者:請將指令加到 ~/.bashrc
    通常是將一些變數設定在此,讓terminal開啟時有一些環境變數可以用。
    如:
        export PATH=$JAVA_HOME/bin:$PATH

2. 針對系統開機時自動執行:請將指令加到 /etc/rc.local
    此檔案本身就有範例。