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