本篇沒什么清晰的目的,只是解釋一下前面的幾個問題,并提出一些新的目標。
在“asgard項目遺留問題”中,我簡單提到了幾個問題,并且想了一些解決方案。
其中,最首要解決的是第2條“服務對象的大小”和第5條“全局元信息”,這2條將影響到調用機制、call對象的生成。一個調用將生成一個call對象,由線程池來處理,同步調用將由異步調用來模擬。
在call對象中,保存了所有in/out參數的包裝對象。當處理同步調用時,由于out參數可能是一個棧上對象(或簡單類型,這里統稱對象),所以需要另一個包裝類——outret模板類,它保存out參數的引用。
當同步調用發生時,生成一個call對象(當然out參數的引用已經包含在里面),把這個call對象交給線程池處理,調用的線程阻塞等待調用結束后被喚醒,這就是所謂的異步調用模擬同步調用。由于異步調用被包裝起來了,所以在調用者看來跟同步調用沒什么區別。當然這個動作并非必要,完全可以不使用模擬,而采用真正的同步調用,只是看到ICE是這么實現的,心癢癢而已。
asgard的目標是把現有的系統功能包裝成為服務,所以在通用方面我考慮得比較多。
比如服務端要開放下面這樣一個服務:
service StringService
{
Method <string(inout<string>, in<string>)> strcat;
Method <string(inout<string>, in<string>, in<uint>)> strncat;
};
并且把C標準庫中的strcat和strncat作為這2個方法的實現。
看一下存在哪些問題?
1、函數第1個參數如果直接映射為string,在服務端將出現緩沖區溢出。
2、C標準庫中的strcat返回值是一個指針,它指向strcat的第一個參數(搞這個標準庫的人是不是沒想過這個返回值多么沒用啊??直接返回一個操作的長度不是更好?),在服務端發回客戶端時,這個并不需要被發回來,因為strcat的第1個參數已經能帶回操作后的內容了。
3、strncat的第3個參數表示第1個緩沖區參數的長度,如果能把它和第1個參數合起來用一個buffer對象表示,就能省事了。
理想情況下,我們的服務對象這樣來寫:
service StringService
{
Method <void(inout< buffer<char> >, in<string>)> strcat;
Method <void(inout< buffer<char> >, in<string>)> strncat;
};
我們的目的是把老的代碼包裝成新鮮時髦的服務,當然不用保留老式代碼中的指針,以及使用指針和長度2個值來表示一個緩沖區的做法。buffer類在構造時要接受一個size_t參數,指定緩沖區的大小。
這在服務端將產生映射問題,由于這個Method定義的形式和C標準庫中的函數形式不一致。
我想應該去實現一個適配器模板類,比如:
this->strcat.setFunction (adapter<char*(char*, const char*), convert<void, 0>(inout< buffer<char> >, in<string>)> (::strcat));
this->strncat.setFunction (adapter<char*(char*, const char*, size_t), convert<void, 0>(inout< buffer<char> >, in<string>, length<in<uint>, 1>)> (::strncat));
convert<void, 0>表示把第0個參數(這里指返回值)轉成void類型,length<in<uint>, 1>表示這個參數類型是int<uint>,它是從第1個參數中提取的長度,大致就是使用這種規則,語法可能以后會有變動。
這點內容是我幾個月前就在考慮的,也是我想做這個項目的動機,不過直到最近一段時間才從可行性方面仔細考慮。
通過前面幾個模板的練習,現在已經大致知道哪些東西是可以用模板做出來,哪些不能使用模板,這應該是最大的收獲了。很多東西單靠模板或是虛函數都不好完成,但結合起來就能產生意想不到的效果。
又仔細想了一下,上面的代碼應該還可以修改簡化:
this->strcat.setFunction (adapter<convert<void, 0>(inout< buffer<char> >, in<string>)> ( ) (::strcat));
this->strncat.setFunction (adapter<convert<void, 0>(inout< buffer<char> >, in<string>, length<in<uint>, 1>)> ( ) (::strncat));
使用一個仿函數來做,函數指針的類型可以從operator ()的參數(模板參數)中推導出來。