Linux® 涓渶甯哥敤鐨勮緭鍏?杈撳嚭錛圛/O錛夋ā鍨嬫槸鍚屾 I/O銆傚湪榪欎釜妯″瀷涓紝褰撹姹傚彂鍑轟箣鍚庯紝搴旂敤紼嬪簭灝變細闃誨錛岀洿鍒拌姹傛弧瓚充負姝€傝繖鏄緢濂界殑涓縐嶈В鍐蟲柟妗堬紝鍥犱負璋冪敤搴旂敤紼嬪簭鍦ㄧ瓑寰?I/O 璇鋒眰瀹屾垚鏃朵笉闇瑕佷嬌鐢ㄤ換浣曚腑澶鐞嗗崟鍏冿紙CPU錛夈備絾鏄湪鏌愪簺鎯呭喌涓紝I/O 璇鋒眰鍙兘闇瑕佷笌鍏朵粬榪涚▼浜х敓浜ゅ彔銆傚彲縐繪鎿嶄綔緋葷粺鎺ュ彛錛圥OSIX錛夊紓姝?I/O錛圓IO錛夊簲鐢ㄧ▼搴忔帴鍙o紙API錛夊氨鎻愪緵浜嗚繖縐嶅姛鑳姐傚湪鏈枃涓紝鎴戜滑灝嗗榪欎釜 API 姒傝榪涜浠嬬粛錛屽茍鏉ヤ簡瑙d竴涓嬪浣曚嬌鐢ㄥ畠銆?/blockquote>
AIO 綆浠?
Linux 寮傛 I/O 鏄?Linux 鍐呮牳涓彁渚涚殑涓涓浉褰撴柊鐨勫寮恒傚畠鏄?2.6 鐗堟湰鍐呮牳鐨勪竴涓爣鍑嗙壒鎬э紝浣嗘槸鎴戜滑鍦?2.4 鐗堟湰鍐呮牳鐨勮ˉ涓佷腑涔熷彲浠ユ壘鍒板畠銆侫IO 鑳屽悗鐨勫熀鏈濇兂鏄厑璁歌繘紼嬪彂璧峰緢澶?I/O 鎿嶄綔錛岃屼笉鐢ㄩ樆濉炴垨絳夊緟浠諱綍鎿嶄綔瀹屾垚銆傜◢鍚庢垨鍦ㄦ帴鏀跺埌 I/O 鎿嶄綔瀹屾垚鐨勯氱煡鏃訛紝榪涚▼灝卞彲浠ユ绱?I/O 鎿嶄綔鐨勭粨鏋溿?/p>
I/O 妯″瀷
鍦ㄦ繁鍏ヤ粙緇?AIO API 涔嬪墠錛岃鎴戜滑鍏堟潵鎺㈢儲涓涓?Linux 涓婂彲浠ヤ嬌鐢ㄧ殑涓嶅悓 I/O 妯″瀷銆傝繖騫朵笉鏄竴涓灝界殑浠嬬粛錛屼絾鏄垜浠皢璇曞浘浠嬬粛鏈甯哥敤鐨勪竴浜涙ā鍨嬫潵瑙i噴瀹冧滑涓庡紓姝?I/O 涔嬮棿鐨勫尯鍒傚浘 1 緇欏嚭浜嗗悓姝ュ拰寮傛妯″瀷錛屼互鍙婇樆濉炲拰闈為樆濉炵殑妯″瀷銆?/p>
鍥?1. 鍩烘湰 Linux I/O 妯″瀷鐨勭畝鍗曠煩闃?/strong>
姣忎釜 I/O 妯″瀷閮芥湁鑷繁鐨勪嬌鐢ㄦā寮忥紝瀹冧滑瀵逛簬鐗瑰畾鐨勫簲鐢ㄧ▼搴忛兘鏈夎嚜宸辯殑浼樼偣銆傛湰鑺傚皢綆瑕佸鍏朵竴涓榪涜浠嬬粛銆?/p>
鍚屾闃誨 I/O
 |
I/O 瀵嗛泦鍨嬩笌 CPU 瀵嗛泦鍨嬭繘紼嬬殑姣旇緝
I/O 瀵嗛泦鍨嬭繘紼嬫墍鎵ц鐨?I/O 鎿嶄綔姣旀墽琛岀殑澶勭悊鎿嶄綔鏇村銆侰PU 瀵嗛泦鍨嬬殑榪涚▼鎵鎵ц鐨勫鐞嗘搷浣滄瘮 I/O 鎿嶄綔鏇村銆侺inux 2.6 鐨勮皟搴﹀櫒瀹為檯涓婃洿鍔犲亸鐖?I/O 瀵嗛泦鍨嬬殑榪涚▼錛屽洜涓哄畠浠氬父浼氬彂璧蜂竴涓?I/O 鎿嶄綔錛岀劧鍚庤繘琛岄樆濉烇紝榪欏氨鎰忓懗鐫鍏朵粬宸ヤ綔閮藉彲浠ュ湪涓よ呬箣闂存湁鏁堝湴浜ら敊榪涜銆?/p>
|
|
鏈甯哥敤鐨勪竴涓ā鍨嬫槸鍚屾闃誨 I/O 妯″瀷銆傚湪榪欎釜妯″瀷涓紝鐢ㄦ埛絀洪棿鐨勫簲鐢ㄧ▼搴忔墽琛屼竴涓郴緇熻皟鐢紝榪欎細瀵艱嚧搴旂敤紼嬪簭闃誨銆傝繖鎰忓懗鐫搴旂敤紼嬪簭浼氫竴鐩撮樆濉烇紝鐩村埌緋葷粺璋冪敤瀹屾垚涓烘錛堟暟鎹紶杈撳畬鎴愭垨鍙戠敓閿欒錛夈傝皟鐢ㄥ簲鐢ㄧ▼搴忓浜庝竴縐嶄笉鍐嶆秷璐?CPU 鑰屽彧鏄畝鍗曠瓑寰呭搷搴旂殑鐘舵侊紝鍥犳浠庡鐞嗙殑瑙掑害鏉ョ湅錛岃繖鏄潪甯告湁鏁堢殑銆?/p>
鍥?2 緇欏嚭浜嗕紶緇熺殑闃誨 I/O 妯″瀷錛岃繖涔熸槸鐩墠搴旂敤紼嬪簭涓渶涓哄父鐢ㄧ殑涓縐嶆ā鍨嬨傚叾琛屼負闈炲父瀹規槗鐞嗚В錛屽叾鐢ㄦ硶瀵逛簬鍏稿瀷鐨勫簲鐢ㄧ▼搴忔潵璇撮兘闈炲父鏈夋晥銆傚湪璋冪敤 read
緋葷粺璋冪敤鏃訛紝搴旂敤紼嬪簭浼氶樆濉炲茍瀵瑰唴鏍歌繘琛屼笂涓嬫枃鍒囨崲銆傜劧鍚庝細瑙﹀彂璇繪搷浣滐紝褰撳搷搴旇繑鍥炴椂錛堜粠鎴戜滑姝e湪浠庝腑璇誨彇鐨勮澶囦腑榪斿洖錛夛紝鏁版嵁灝辮縐誨姩鍒扮敤鎴風┖闂寸殑緙撳啿鍖轟腑銆傜劧鍚庡簲鐢ㄧ▼搴忓氨浼氳В闄ら樆濉烇紙read
璋冪敤榪斿洖錛夈?/p>
鍥?2. 鍚屾闃誨 I/O 妯″瀷鐨勫吀鍨嬫祦紼?/strong>
浠庡簲鐢ㄧ▼搴忕殑瑙掑害鏉ヨ錛?code>read 璋冪敤浼氬歡緇緢闀挎椂闂淬傚疄闄呬笂錛屽湪鍐呮牳鎵ц璇繪搷浣滃拰鍏朵粬宸ヤ綔鏃訛紝搴旂敤紼嬪簭鐨勭‘浼氳闃誨銆?/p>
鍚屾闈為樆濉?I/O
鍚屾闃誨 I/O 鐨勪竴縐嶆晥鐜囩◢浣庣殑鍙樼鏄悓姝ラ潪闃誨 I/O銆傚湪榪欑妯″瀷涓紝璁懼鏄互闈為樆濉炵殑褰㈠紡鎵撳紑鐨勩傝繖鎰忓懗鐫 I/O 鎿嶄綔涓嶄細绔嬪嵆瀹屾垚錛?code>read 鎿嶄綔鍙兘浼氳繑鍥炰竴涓敊璇唬鐮侊紝璇存槑榪欎釜鍛戒護涓嶈兘绔嬪嵆婊¤凍錛?code>EAGAIN 鎴?EWOULDBLOCK
錛夛紝濡傚浘 3 鎵紺恒?/p>
鍥?3. 鍚屾闈為樆濉?I/O 妯″瀷鐨勫吀鍨嬫祦紼?/strong>
闈為樆濉炵殑瀹炵幇鏄?I/O 鍛戒護鍙兘騫朵笉浼氱珛鍗蟲弧瓚籌紝闇瑕佸簲鐢ㄧ▼搴忚皟鐢ㄨ澶氭鏉ョ瓑寰呮搷浣滃畬鎴愩傝繖鍙兘鏁堢巼涓嶉珮錛屽洜涓哄湪寰堝鎯呭喌涓嬶紝褰撳唴鏍告墽琛岃繖涓懡浠ゆ椂錛屽簲鐢ㄧ▼搴忓繀欏昏榪涜蹇欑絳夊緟錛岀洿鍒版暟鎹彲鐢ㄤ負姝紝鎴栬呰瘯鍥炬墽琛屽叾浠栧伐浣溿傛濡傚浘 3 鎵紺虹殑涓鏍鳳紝榪欎釜鏂規硶鍙互寮曞叆 I/O 鎿嶄綔鐨勫歡鏃訛紝鍥犱負鏁版嵁鍦ㄥ唴鏍鎬腑鍙樹負鍙敤鍒扮敤鎴瘋皟鐢?read
榪斿洖鏁版嵁涔嬮棿瀛樺湪涓瀹氱殑闂撮殧錛岃繖浼氬鑷存暣浣撴暟鎹悶鍚愰噺鐨勯檷浣庛?/p>
寮傛闃誨 I/O
鍙﹀涓涓樆濉炶В鍐蟲柟妗堟槸甯︽湁闃誨閫氱煡鐨勯潪闃誨 I/O銆傚湪榪欑妯″瀷涓紝閰嶇疆鐨勬槸闈為樆濉?I/O錛岀劧鍚庝嬌鐢ㄩ樆濉?select
緋葷粺璋冪敤鏉ョ‘瀹氫竴涓?I/O 鎻忚堪絎︿綍鏃舵湁鎿嶄綔銆備嬌 select
璋冪敤闈炲父鏈夎叮鐨勬槸瀹冨彲浠ョ敤鏉ヤ負澶氫釜鎻忚堪絎︽彁渚涢氱煡錛岃屼笉浠呬粎涓轟竴涓弿榪扮鎻愪緵閫氱煡銆傚浜庢瘡涓彁紺虹鏉ヨ錛屾垜浠彲浠ヨ姹傝繖涓弿榪扮鍙互鍐欐暟鎹佹湁璇繪暟鎹彲鐢ㄤ互鍙婃槸鍚﹀彂鐢熼敊璇殑閫氱煡銆?/p>
鍥?4. 寮傛闃誨 I/O 妯″瀷鐨勫吀鍨嬫祦紼?(select)
select
璋冪敤鐨勪富瑕侀棶棰樻槸瀹冪殑鏁堢巼涓嶆槸闈炲父楂樸傚敖綆¤繖鏄紓姝ラ氱煡浣跨敤鐨勪竴縐嶆柟渚挎ā鍨嬶紝浣嗘槸瀵逛簬楂樻ц兘鐨?I/O 鎿嶄綔鏉ヨ涓嶅緩璁嬌鐢ㄣ?/p>
寮傛闈為樆濉?I/O錛圓IO錛?
鏈鍚庯紝寮傛闈為樆濉?I/O 妯″瀷鏄竴縐嶅鐞嗕笌 I/O 閲嶅彔榪涜鐨勬ā鍨嬨傝璇鋒眰浼氱珛鍗寵繑鍥烇紝璇存槑 read
璇鋒眰宸茬粡鎴愬姛鍙戣搗浜嗐傚湪鍚庡彴瀹屾垚璇繪搷浣滄椂錛屽簲鐢ㄧ▼搴忕劧鍚庝細鎵ц鍏朵粬澶勭悊鎿嶄綔銆傚綋 read
鐨勫搷搴斿埌杈炬椂錛屽氨浼氫駭鐢熶竴涓俊鍙鋒垨鎵ц涓涓熀浜庣嚎紼嬬殑鍥炶皟鍑芥暟鏉ュ畬鎴愯繖嬈?I/O 澶勭悊榪囩▼銆?/p>
鍥?5. 寮傛闈為樆濉?I/O 妯″瀷鐨勫吀鍨嬫祦紼?/strong>
鍦ㄤ竴涓繘紼嬩腑涓轟簡鎵ц澶氫釜 I/O 璇鋒眰鑰屽璁$畻鎿嶄綔鍜?I/O 澶勭悊榪涜閲嶅彔澶勭悊鐨勮兘鍔涘埄鐢ㄤ簡澶勭悊閫熷害涓?I/O 閫熷害涔嬮棿鐨勫樊寮傘傚綋涓涓垨澶氫釜 I/O 璇鋒眰鎸傝搗鏃訛紝CPU 鍙互鎵ц鍏朵粬浠誨姟錛涙垨鑰呮洿涓哄父瑙佺殑鏄紝鍦ㄥ彂璧峰叾浠?I/O 鐨勫悓鏃跺宸茬粡瀹屾垚鐨?I/O 榪涜鎿嶄綔銆?/p>
涓嬩竴鑺傚皢娣卞叆浠嬬粛榪欑妯″瀷錛屾帰绱㈣繖縐嶆ā鍨嬩嬌鐢ㄧ殑 API錛岀劧鍚庡睍紺哄嚑涓懡浠ゃ?/p>
寮傛 I/O 鐨勫姩鏈?
浠庡墠闈?I/O 妯″瀷鐨勫垎綾諱腑錛屾垜浠彲浠ョ湅鍑?AIO 鐨勫姩鏈恒傝繖縐嶉樆濉炴ā鍨嬮渶瑕佸湪 I/O 鎿嶄綔寮濮嬫椂闃誨搴旂敤紼嬪簭銆傝繖鎰忓懗鐫涓嶅彲鑳藉悓鏃墮噸鍙犺繘琛屽鐞嗗拰 I/O 鎿嶄綔銆傚悓姝ラ潪闃誨妯″瀷鍏佽澶勭悊鍜?I/O 鎿嶄綔閲嶅彔榪涜錛屼絾鏄繖闇瑕佸簲鐢ㄧ▼搴忔牴鎹噸鐜扮殑瑙勫垯鏉ユ鏌?I/O 鎿嶄綔鐨勭姸鎬併傝繖鏍峰氨鍓╀笅寮傛闈為樆濉?I/O 浜嗭紝瀹冨厑璁稿鐞嗗拰 I/O 鎿嶄綔閲嶅彔榪涜錛屽寘鎷?I/O 鎿嶄綔瀹屾垚鐨勯氱煡銆?/p>
闄や簡闇瑕侀樆濉炰箣澶栵紝select
鍑芥暟鎵鎻愪緵鐨勫姛鑳斤紙寮傛闃誨 I/O錛変笌 AIO 綾諱技銆備笉榪囷紝瀹冩槸瀵歸氱煡浜嬩歡榪涜闃誨錛岃屼笉鏄 I/O 璋冪敤榪涜闃誨銆?/p>
Linux 涓婄殑 AIO 綆浠?
鏈妭灝嗘帰绱?Linux 鐨勫紓姝?I/O 妯″瀷錛屼粠鑰屽府鍔╂垜浠悊瑙e浣曞湪搴旂敤紼嬪簭涓嬌鐢ㄨ繖縐嶆妧鏈?/p>
鍦ㄤ紶緇熺殑 I/O 妯″瀷涓紝鏈変竴涓嬌鐢ㄦ儫涓鍙ユ焺鏍囪瘑鐨?I/O 閫氶亾銆傚湪 UNIX® 涓紝榪欎簺鍙ユ焺鏄枃浠舵弿榪扮錛堣繖瀵圭瓑鍚屼簬鏂囦歡銆佺閬撱佸鎺ュ瓧絳夌瓑錛夈傚湪闃誨 I/O 涓紝鎴戜滑鍙戣搗浜嗕竴嬈′紶杈撴搷浣滐紝褰撲紶杈撴搷浣滃畬鎴愭垨鍙戠敓閿欒鏃訛紝緋葷粺璋冪敤灝變細榪斿洖銆?/p>
 |
Linux 涓婄殑 AIO
AIO 鍦?2.5 鐗堟湰鐨勫唴鏍鎬腑棣栨鍑虹幇錛岀幇鍦ㄥ凡緇忔槸 2.6 鐗堟湰鐨勪駭鍝佸唴鏍哥殑涓涓爣鍑嗙壒鎬т簡銆?/p>
|
|
鍦ㄥ紓姝ラ潪闃誨 I/O 涓紝鎴戜滑鍙互鍚屾椂鍙戣搗澶氫釜浼犺緭鎿嶄綔銆傝繖闇瑕佹瘡涓紶杈撴搷浣滈兘鏈夋儫涓鐨勪笂涓嬫枃錛岃繖鏍鋒垜浠墠鑳藉湪瀹冧滑瀹屾垚鏃跺尯鍒嗗埌搴曟槸鍝釜浼犺緭鎿嶄綔瀹屾垚浜嗐傚湪 AIO 涓紝榪欐槸涓涓?aiocb
錛圓IO I/O Control Block錛夌粨鏋勩傝繖涓粨鏋勫寘鍚簡鏈夊叧浼犺緭鐨勬墍鏈変俊鎭紝鍖呮嫭涓烘暟鎹噯澶囩殑鐢ㄦ埛緙撳啿鍖恒傚湪浜х敓 I/O 錛堢О涓哄畬鎴愶級閫氱煡鏃訛紝aiocb
緇撴瀯灝辮鐢ㄦ潵鎯熶竴鏍囪瘑鎵瀹屾垚鐨?I/O 鎿嶄綔銆傝繖涓?API 鐨勫睍紺烘樉紺轟簡濡備綍浣跨敤瀹冦?/p>
AIO API
AIO 鎺ュ彛鐨?API 闈炲父綆鍗曪紝浣嗘槸瀹冧負鏁版嵁浼犺緭鎻愪緵浜嗗繀闇鐨勫姛鑳斤紝騫剁粰鍑轟簡涓や釜涓嶅悓鐨勯氱煡妯″瀷銆傝〃 1 緇欏嚭浜?AIO 鐨勬帴鍙e嚱鏁幫紝鏈妭紼嶅悗浼氭洿璇︾粏榪涜浠嬬粛銆?/p>
琛?1. AIO 鎺ュ彛 API
API 鍑芥暟 |
璇存槑 |
aio_read |
璇鋒眰寮傛璇繪搷浣?/td>
|
aio_error |
媯鏌ュ紓姝ヨ姹傜殑鐘舵?/td>
|
aio_return |
鑾峰緱瀹屾垚鐨勫紓姝ヨ姹傜殑榪斿洖鐘舵?/td>
|
aio_write |
璇鋒眰寮傛鍐欐搷浣?/td>
|
aio_suspend |
鎸傝搗璋冪敤榪涚▼錛岀洿鍒頒竴涓垨澶氫釜寮傛璇鋒眰宸茬粡瀹屾垚錛堟垨澶辮觸錛?/td>
|
aio_cancel |
鍙栨秷寮傛 I/O 璇鋒眰 |
lio_listio |
鍙戣搗涓緋誨垪 I/O 鎿嶄綔 |
姣忎釜 API 鍑芥暟閮戒嬌鐢?aiocb
緇撴瀯寮濮嬫垨媯鏌ャ傝繖涓粨鏋勬湁寰堝鍏冪礌錛屼絾鏄竻鍗?1 浠呬粎緇欏嚭浜嗛渶瑕侊紙鎴栧彲浠ワ級浣跨敤鐨勫厓绱犮?/p>
娓呭崟 1. aiocb 緇撴瀯涓浉鍏崇殑鍩?
struct aiocb {
int aio_fildes; // File Descriptor
int aio_lio_opcode; // Valid only for lio_listio (r/w/nop)
volatile void *aio_buf; // Data Buffer
size_t aio_nbytes; // Number of Bytes in Data Buffer
struct sigevent aio_sigevent; // Notification Structure
/* Internal fields */
...
};
|
sigevent
緇撴瀯鍛婅瘔 AIO 鍦?I/O 鎿嶄綔瀹屾垚鏃跺簲璇ユ墽琛屼粈涔堟搷浣溿傛垜浠皢鍦?AIO 鐨勫睍紺轟腑瀵硅繖涓粨鏋勮繘琛屾帰绱€傜幇鍦ㄦ垜浠皢灞曠ず鍚勪釜 AIO 鐨?API 鍑芥暟鏄浣曞伐浣滅殑錛屼互鍙婃垜浠簲璇ュ浣曚嬌鐢ㄥ畠浠?/p>
aio_read
aio_read
鍑芥暟璇鋒眰瀵逛竴涓湁鏁堢殑鏂囦歡鎻忚堪絎﹁繘琛屽紓姝ヨ鎿嶄綔銆傝繖涓枃浠舵弿榪扮鍙互琛ㄧず涓涓枃浠躲佸鎺ュ瓧鐢氳嚦綆¢亾銆?code>aio_read 鍑芥暟鐨勫師鍨嬪涓嬶細
int aio_read( struct aiocb *aiocbp );
|
aio_read
鍑芥暟鍦ㄨ姹傝繘琛屾帓闃熶箣鍚庝細绔嬪嵆榪斿洖銆傚鏋滄墽琛屾垚鍔燂紝榪斿洖鍊煎氨涓?0錛涘鏋滃嚭鐜伴敊璇紝榪斿洖鍊煎氨涓?-1錛屽茍璁劇疆 errno
鐨勫箋?/p>
瑕佹墽琛岃鎿嶄綔錛屽簲鐢ㄧ▼搴忓繀欏誨 aiocb
緇撴瀯榪涜鍒濆鍖栥備笅闈㈣繖涓畝鐭殑渚嬪瓙灝卞睍紺轟簡濡備綍濉厖 aiocb
璇鋒眰緇撴瀯錛屽茍浣跨敤 aio_read
鏉ユ墽琛屽紓姝ヨ璇鋒眰錛堢幇鍦ㄦ殏鏃跺拷鐣ラ氱煡錛夋搷浣溿傚畠榪樺睍紺轟簡 aio_error
鐨勭敤娉曪紝涓嶈繃鎴戜滑灝嗙◢鍚庡啀浣滆В閲娿?/p>
娓呭崟 2. 浣跨敤 aio_read 榪涜寮傛璇繪搷浣滅殑渚嬪瓙
#include <aio.h>
...
int fd, ret;
struct aiocb my_aiocb;
fd = open( "file.txt", O_RDONLY );
if (fd < 0) perror("open");
/* Zero out the aiocb structure (recommended) */
bzero( (char *)&my_aiocb, sizeof(struct aiocb) );
/* Allocate a data buffer for the aiocb request */
my_aiocb.aio_buf = malloc(BUFSIZE+1);
if (!my_aiocb.aio_buf) perror("malloc");
/* Initialize the necessary fields in the aiocb */
my_aiocb.aio_fildes = fd;
my_aiocb.aio_nbytes = BUFSIZE;
my_aiocb.aio_offset = 0;
ret = aio_read( &my_aiocb );
if (ret < 0) perror("aio_read");
while ( aio_error( &my_aiocb ) == EINPROGRESS ) ;
if ((ret = aio_return( &my_iocb )) > 0) {
/* got ret bytes on the read */
} else {
/* read failed, consult errno */
}
|
鍦ㄦ竻鍗?2 涓紝鍦ㄦ墦寮瑕佷粠涓鍙栨暟鎹殑鏂囦歡涔嬪悗錛屾垜浠氨娓呯┖浜?aiocb
緇撴瀯錛岀劧鍚庡垎閰嶄竴涓暟鎹紦鍐插尯銆傚茍灝嗗榪欎釜鏁版嵁緙撳啿鍖虹殑寮曠敤鏀懼埌 aio_buf
涓傜劧鍚庯紝鎴戜滑灝?aio_nbytes
鍒濆鍖栨垚緙撳啿鍖虹殑澶у皬銆傚茍灝?aio_offset
璁劇疆鎴?0錛堣鏂囦歡涓殑絎竴涓亸縐婚噺錛夈傛垜浠皢 aio_fildes
璁劇疆涓轟粠涓鍙栨暟鎹殑鏂囦歡鎻忚堪絎︺傚湪璁劇疆榪欎簺鍩熶箣鍚庯紝灝辮皟鐢?aio_read
璇鋒眰榪涜璇繪搷浣溿傛垜浠劧鍚庡彲浠ヨ皟鐢?aio_error
鏉ョ‘瀹?aio_read
鐨勭姸鎬併傚彧瑕佺姸鎬佹槸 EINPROGRESS
錛屽氨涓鐩村繖紕岀瓑寰咃紝鐩村埌鐘舵佸彂鐢熷彉鍖栦負姝€傜幇鍦紝璇鋒眰鍙兘鎴愬姛錛屼篃鍙兘澶辮觸銆?/p>
娉ㄦ剰浣跨敤榪欎釜 API 涓庢爣鍑嗙殑搴撳嚱鏁頒粠鏂囦歡涓鍙栧唴瀹規槸闈炲父鐩鎬技鐨勩傞櫎浜?aio_read
鐨勪竴浜涘紓姝ョ壒鎬т箣澶栵紝鍙﹀涓涓尯鍒槸璇繪搷浣滃亸縐婚噺鐨勮緗傚湪浼犵粺鐨?read
璋冪敤涓紝鍋忕Щ閲忔槸鍦ㄦ枃浠舵弿榪扮涓婁笅鏂囦腑榪涜緇存姢鐨勩傚浜庢瘡涓鎿嶄綔鏉ヨ錛屽亸縐婚噺閮介渶瑕佽繘琛屾洿鏂幫紝榪欐牱鍚庣畫鐨勮鎿嶄綔鎵嶈兘瀵逛笅涓鍧楁暟鎹繘琛屽鍧銆傚浜庡紓姝?I/O 鎿嶄綔鏉ヨ榪欐槸涓嶅彲鑳界殑錛屽洜涓烘垜浠彲浠ュ悓鏃舵墽琛屽緢澶氳璇鋒眰錛屽洜姝ゅ繀欏諱負姣忎釜鐗瑰畾鐨勮璇鋒眰閮芥寚瀹氬亸縐婚噺銆?/p>
aio_error
aio_error
鍑芥暟琚敤鏉ョ‘瀹氳姹傜殑鐘舵併傚叾鍘熷瀷濡備笅錛?/p>
int aio_error( struct aiocb *aiocbp );
|
榪欎釜鍑芥暟鍙互榪斿洖浠ヤ笅鍐呭錛?/p>
EINPROGRESS
錛岃鏄庤姹傚皻鏈畬鎴?
ECANCELLED
錛岃鏄庤姹傝搴旂敤紼嬪簭鍙栨秷浜?
-1
錛岃鏄庡彂鐢熶簡閿欒錛屽叿浣撻敊璇師鍥犲彲浠ユ煡闃?errno
aio_return
寮傛 I/O 鍜屾爣鍑嗗潡 I/O 涔嬮棿鐨勫彟澶栦竴涓尯鍒槸鎴戜滑涓嶈兘绔嬪嵆璁塊棶榪欎釜鍑芥暟鐨勮繑鍥炵姸鎬侊紝鍥犱負鎴戜滑騫舵病鏈夐樆濉炲湪 read
璋冪敤涓娿傚湪鏍囧噯鐨?read
璋冪敤涓紝榪斿洖鐘舵佹槸鍦ㄨ鍑芥暟榪斿洖鏃舵彁渚涚殑銆備絾鏄湪寮傛 I/O 涓紝鎴戜滑瑕佷嬌鐢?aio_return
鍑芥暟銆傝繖涓嚱鏁扮殑鍘熷瀷濡備笅錛?/p>
ssize_t aio_return( struct aiocb *aiocbp );
|
鍙湁鍦?aio_error
璋冪敤紜畾璇鋒眰宸茬粡瀹屾垚錛堝彲鑳芥垚鍔燂紝涔熷彲鑳藉彂鐢熶簡閿欒錛変箣鍚庯紝鎵嶄細璋冪敤榪欎釜鍑芥暟銆?code>aio_return 鐨勮繑鍥炲煎氨絳変環浜庡悓姝ユ儏鍐典腑 read
鎴?write
緋葷粺璋冪敤鐨勮繑鍥炲鹼紙鎵浼犺緭鐨勫瓧鑺傛暟錛屽鏋滃彂鐢熼敊璇紝榪斿洖鍊煎氨涓?-1
錛夈?/p>
aio_write
aio_write
鍑芥暟鐢ㄦ潵璇鋒眰涓涓紓姝ュ啓鎿嶄綔銆傚叾鍑芥暟鍘熷瀷濡備笅錛?
int aio_write( struct aiocb *aiocbp );
|
aio_write
鍑芥暟浼氱珛鍗寵繑鍥烇紝璇存槑璇鋒眰宸茬粡榪涜鎺掗槦錛堟垚鍔熸椂榪斿洖鍊間負 0
錛屽け璐ユ椂榪斿洖鍊間負 -1
錛屽茍鐩稿簲鍦拌緗?errno
錛夈?/p>
榪欎笌 read
緋葷粺璋冪敤綾諱技錛屼絾鏄湁涓鐐逛笉涓鏍風殑琛屼負闇瑕佹敞鎰忋傚洖鎯充竴涓嬪浜?read
璋冪敤鏉ヨ錛岃浣跨敤鐨勫亸縐婚噺鏄潪甯擱噸瑕佺殑銆傜劧鑰岋紝瀵逛簬 write
鏉ヨ錛岃繖涓亸縐婚噺鍙湁鍦ㄦ病鏈夎緗?O_APPEND
閫夐」鐨勬枃浠朵笂涓嬫枃涓墠浼氶潪甯擱噸瑕併傚鏋滆緗簡 O_APPEND
錛岄偅涔堣繖涓亸縐婚噺灝變細琚拷鐣ワ紝鏁版嵁閮戒細琚檮鍔犲埌鏂囦歡鐨勬湯灝俱傚惁鍒欙紝aio_offset
鍩熷氨紜畾浜嗘暟鎹湪瑕佸啓鍏ョ殑鏂囦歡涓殑鍋忕Щ閲忋?/p>
aio_suspend
鎴戜滑鍙互浣跨敤 aio_suspend
鍑芥暟鏉ユ寕璧鳳紙鎴栭樆濉烇級璋冪敤榪涚▼錛岀洿鍒板紓姝ヨ姹傚畬鎴愪負姝紝姝ゆ椂浼氫駭鐢熶竴涓俊鍙鳳紝鎴栬呭彂鐢熷叾浠栬秴鏃舵搷浣溿傝皟鐢ㄨ呮彁渚涗簡涓涓?aiocb
寮曠敤鍒楄〃錛屽叾涓換浣曚竴涓畬鎴愰兘浼氬鑷?aio_suspend
榪斿洖銆?aio_suspend
鐨勫嚱鏁板師鍨嬪涓嬶細
int aio_suspend( const struct aiocb *const cblist[],
int n, const struct timespec *timeout );
|
aio_suspend
鐨勪嬌鐢ㄩ潪甯哥畝鍗曘傛垜浠鎻愪緵涓涓?aiocb
寮曠敤鍒楄〃銆傚鏋滀換浣曚竴涓畬鎴愪簡錛岃繖涓皟鐢ㄥ氨浼氳繑鍥?0
銆傚惁鍒欏氨浼氳繑鍥?-1
錛岃鏄庡彂鐢熶簡閿欒銆傝鍙傜湅娓呭崟 3銆?/p>
娓呭崟 3. 浣跨敤 aio_suspend 鍑芥暟闃誨寮傛 I/O
struct aioct *cblist[MAX_LIST]
/* Clear the list. */
bzero( (char *)cblist, sizeof(cblist) );
/* Load one or more references into the list */
cblist[0] = &my_aiocb;
ret = aio_read( &my_aiocb );
ret = aio_suspend( cblist, MAX_LIST, NULL );
|
娉ㄦ剰錛?code>aio_suspend 鐨勭浜屼釜鍙傛暟鏄?cblist
涓厓绱犵殑涓暟錛岃屼笉鏄?aiocb
寮曠敤鐨勪釜鏁般?code>cblist 涓換浣?NULL
鍏冪礌閮戒細琚?aio_suspend
蹇界暐銆?/p>
濡傛灉涓?aio_suspend
鎻愪緵浜嗚秴鏃訛紝鑰岃秴鏃舵儏鍐電殑紜彂鐢熶簡錛岄偅涔堝畠灝變細榪斿洖 -1
錛?code>errno 涓細鍖呭惈 EAGAIN
銆?/p>
aio_cancel
aio_cancel
鍑芥暟鍏佽鎴戜滑鍙栨秷瀵規煇涓枃浠舵弿榪扮鎵ц鐨勪竴涓垨鎵鏈?I/O 璇鋒眰銆傚叾鍘熷瀷濡備笅錛?/p>
int aio_cancel( int fd, struct aiocb *aiocbp );
|
瑕佸彇娑堜竴涓姹傦紝鎴戜滑闇瑕佹彁渚涙枃浠舵弿榪扮鍜?aiocb
寮曠敤銆傚鏋滆繖涓姹傝鎴愬姛鍙栨秷浜嗭紝閭d箞榪欎釜鍑芥暟灝變細榪斿洖 AIO_CANCELED
銆傚鏋滆姹傚畬鎴愪簡錛岃繖涓嚱鏁板氨浼氳繑鍥?AIO_NOTCANCELED
銆?/p>
瑕佸彇娑堝鏌愪釜緇欏畾鏂囦歡鎻忚堪絎︾殑鎵鏈夎姹傦紝鎴戜滑闇瑕佹彁渚涜繖涓枃浠剁殑鎻忚堪絎︼紝浠ュ強涓涓 aiocbp
鐨?NULL
寮曠敤銆傚鏋滄墍鏈夌殑璇鋒眰閮藉彇娑堜簡錛岃繖涓嚱鏁板氨浼氳繑鍥?AIO_CANCELED
錛涘鏋滆嚦灝戞湁涓涓姹傛病鏈夎鍙栨秷錛岄偅涔堣繖涓嚱鏁板氨浼氳繑鍥?AIO_NOT_CANCELED
錛涘鏋滄病鏈変竴涓姹傚彲浠ヨ鍙栨秷錛岄偅涔堣繖涓嚱鏁板氨浼氳繑鍥?AIO_ALLDONE
銆傛垜浠劧鍚庡彲浠ヤ嬌鐢?aio_error
鏉ラ獙璇佹瘡涓?AIO 璇鋒眰銆傚鏋滆繖涓姹傚凡緇忚鍙栨秷浜嗭紝閭d箞 aio_error
灝變細榪斿洖 -1
錛屽茍涓?errno
浼氳璁劇疆涓?ECANCELED
銆?/p>
lio_listio
鏈鍚庯紝AIO 鎻愪緵浜嗕竴縐嶆柟娉曚嬌鐢?lio_listio
API 鍑芥暟鍚屾椂鍙戣搗澶氫釜浼犺緭銆傝繖涓嚱鏁伴潪甯擱噸瑕侊紝鍥犱負榪欐剰鍛崇潃鎴戜滑鍙互鍦ㄤ竴涓郴緇熻皟鐢紙涓嬈″唴鏍鎬笂涓嬫枃鍒囨崲錛変腑鍚姩澶ч噺鐨?I/O 鎿嶄綔銆備粠鎬ц兘鐨勮搴︽潵鐪嬶紝榪欓潪甯擱噸瑕侊紝鍥犳鍊煎緱鎴戜滑鑺辯偣鏃墮棿鎺㈢儲涓涓嬨?code>lio_listio API 鍑芥暟鐨勫師鍨嬪涓嬶細
int lio_listio( int mode, struct aiocb *list[], int nent,
struct sigevent *sig );
|
mode
鍙傛暟鍙互鏄?LIO_WAIT
鎴?LIO_NOWAIT
銆?code>LIO_WAIT 浼氶樆濉炶繖涓皟鐢紝鐩村埌鎵鏈夌殑 I/O 閮藉畬鎴愪負姝€傚湪鎿嶄綔榪涜鎺掗槦涔嬪悗錛?code>LIO_NOWAIT 灝變細榪斿洖銆?code>list 鏄竴涓?aiocb
寮曠敤鐨勫垪琛紝鏈澶у厓绱犵殑涓暟鏄敱 nent
瀹氫箟鐨勩傛敞鎰?list
鐨勫厓绱犲彲浠ヤ負 NULL
錛?code>lio_listio 浼氬皢鍏跺拷鐣ャ?code>sigevent 寮曠敤瀹氫箟浜嗗湪鎵鏈?I/O 鎿嶄綔閮藉畬鎴愭椂浜х敓淇″彿鐨勬柟娉曘?/p>
瀵逛簬 lio_listio
鐨勮姹備笌浼犵粺鐨?read
鎴?write
璇鋒眰鍦ㄥ繀欏繪寚瀹氱殑鎿嶄綔鏂歸潰紼嶆湁涓嶅悓錛屽娓呭崟 4 鎵紺恒?/p>
娓呭崟 4. 浣跨敤 lio_listio 鍑芥暟鍙戣搗涓緋誨垪璇鋒眰
struct aiocb aiocb1, aiocb2;
struct aiocb *list[MAX_LIST];
...
/* Prepare the first aiocb */
aiocb1.aio_fildes = fd;
aiocb1.aio_buf = malloc( BUFSIZE+1 );
aiocb1.aio_nbytes = BUFSIZE;
aiocb1.aio_offset = next_offset;
aiocb1.aio_lio_opcode = LIO_READ;
...
bzero( (char *)list, sizeof(list) );
list[0] = &aiocb1;
list[1] = &aiocb2;
ret = lio_listio( LIO_WAIT, list, MAX_LIST, NULL );
|
瀵逛簬璇繪搷浣滄潵璇達紝aio_lio_opcode
鍩熺殑鍊間負 LIO_READ
銆傚浜庡啓鎿嶄綔鏉ヨ錛屾垜浠浣跨敤 LIO_WRITE
錛屼笉榪?LIO_NOP
瀵逛簬涓嶆墽琛屾搷浣滄潵璇翠篃鏄湁鏁堢殑銆?/p>
AIO 閫氱煡
鐜板湪鎴戜滑宸茬粡鐪嬭繃浜嗗彲鐢ㄧ殑 AIO 鍑芥暟錛屾湰鑺傚皢娣卞叆浠嬬粛瀵瑰紓姝ラ氱煡鍙互浣跨敤鐨勬柟娉曘傛垜浠皢閫氳繃淇″彿鍜屽嚱鏁板洖璋冩潵鎺㈢儲寮傛鍑芥暟鐨勯氱煡鏈哄埗銆?/p>
浣跨敤淇″彿榪涜寮傛閫氱煡
浣跨敤淇″彿榪涜榪涚▼闂撮氫俊錛圛PC錛夋槸 UNIX 涓殑涓縐嶄紶緇熸満鍒訛紝AIO 涔熷彲浠ユ敮鎸佽繖縐嶆満鍒躲傚湪榪欑鑼冧緥涓紝搴旂敤紼嬪簭闇瑕佸畾涔変俊鍙峰鐞嗙▼搴忥紝鍦ㄤ駭鐢熸寚瀹氱殑淇″彿鏃跺氨浼氳皟鐢ㄨ繖涓鐞嗙▼搴忋傚簲鐢ㄧ▼搴忕劧鍚庨厤緗竴涓紓姝ヨ姹傚皢鍦ㄨ姹傚畬鎴愭椂浜х敓涓涓俊鍙楓備綔涓轟俊鍙蜂笂涓嬫枃鐨勪竴閮ㄥ垎錛岀壒瀹氱殑 aiocb
璇鋒眰琚彁渚涚敤鏉ヨ褰曞涓彲鑳戒細鍑虹幇鐨勮姹傘傛竻鍗?5 灞曠ず浜嗚繖縐嶉氱煡鏂規硶銆?/p>
娓呭崟 5. 浣跨敤淇″彿浣滀負 AIO 璇鋒眰鐨勯氱煡
void setup_io( ... )
{
int fd;
struct sigaction sig_act;
struct aiocb my_aiocb;
...
/* Set up the signal handler */
sigemptyset(&sig_act.sa_mask);
sig_act.sa_flags = SA_SIGINFO;
sig_act.sa_sigaction = aio_completion_handler;
/* Set up the AIO request */
bzero( (char *)&my_aiocb, sizeof(struct aiocb) );
my_aiocb.aio_fildes = fd;
my_aiocb.aio_buf = malloc(BUF_SIZE+1);
my_aiocb.aio_nbytes = BUF_SIZE;
my_aiocb.aio_offset = next_offset;
/* Link the AIO request with the Signal Handler */
my_aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
my_aiocb.aio_sigevent.sigev_signo = SIGIO;
my_aiocb.aio_sigevent.sigev_value.sival_ptr = &my_aiocb;
/* Map the Signal to the Signal Handler */
ret = sigaction( SIGIO, &sig_act, NULL );
...
ret = aio_read( &my_aiocb );
}
void aio_completion_handler( int signo, siginfo_t *info, void *context )
{
struct aiocb *req;
/* Ensure it's our signal */
if (info->si_signo == SIGIO) {
req = (struct aiocb *)info->si_value.sival_ptr;
/* Did the request complete? */
if (aio_error( req ) == 0) {
/* Request completed successfully, get the return status */
ret = aio_return( req );
}
}
return;
}
|
鍦ㄦ竻鍗?5 涓紝鎴戜滑鍦?aio_completion_handler
鍑芥暟涓緗俊鍙峰鐞嗙▼搴忔潵鎹曡幏 SIGIO
淇″彿銆傜劧鍚庡垵濮嬪寲 aio_sigevent
緇撴瀯浜х敓 SIGIO
淇″彿鏉ヨ繘琛岄氱煡錛堣繖鏄氳繃 sigev_notify
涓殑 SIGEV_SIGNAL
瀹氫箟鏉ユ寚瀹氱殑錛夈傚綋璇繪搷浣滃畬鎴愭椂錛屼俊鍙峰鐞嗙▼搴忓氨浠庤淇″彿鐨?si_value
緇撴瀯涓彁鍙栧嚭 aiocb
錛屽茍媯鏌ラ敊璇姸鎬佸拰榪斿洖鐘舵佹潵紜畾 I/O 鎿嶄綔鏄惁瀹屾垚銆?/p>
瀵逛簬鎬ц兘鏉ヨ錛岃繖涓鐞嗙▼搴忎篃鏄氳繃璇鋒眰涓嬩竴嬈″紓姝ヤ紶杈撹岀戶緇繘琛?I/O 鎿嶄綔鐨勭悊鎯沖湴鏂廣傞噰鐢ㄨ繖縐嶆柟寮忥紝鍦ㄤ竴嬈℃暟鎹紶杈撳畬鎴愭椂錛屾垜浠氨鍙互绔嬪嵆寮濮嬩笅涓嬈℃暟鎹紶杈撴搷浣溿?/p>
浣跨敤鍥炶皟鍑芥暟榪涜寮傛閫氱煡
鍙﹀涓縐嶉氱煡鏂瑰紡鏄郴緇熷洖璋冨嚱鏁般傝繖縐嶆満鍒朵笉浼氫負閫氱煡鑰屼駭鐢熶竴涓俊鍙鳳紝鑰屾槸浼氳皟鐢ㄧ敤鎴風┖闂寸殑涓涓嚱鏁版潵瀹炵幇閫氱煡鍔熻兘銆傛垜浠湪 sigevent
緇撴瀯涓緗簡瀵?aiocb
鐨勫紩鐢紝浠庤屽彲浠ユ儫涓鏍囪瘑姝e湪瀹屾垚鐨勭壒瀹氳姹傘傝鍙傜湅娓呭崟 6銆?/p>
娓呭崟 6. 瀵?AIO 璇鋒眰浣跨敤綰跨▼鍥炶皟閫氱煡
void setup_io( ... )
{
int fd;
struct aiocb my_aiocb;
...
/* Set up the AIO request */
bzero( (char *)&my_aiocb, sizeof(struct aiocb) );
my_aiocb.aio_fildes = fd;
my_aiocb.aio_buf = malloc(BUF_SIZE+1);
my_aiocb.aio_nbytes = BUF_SIZE;
my_aiocb.aio_offset = next_offset;
/* Link the AIO request with a thread callback */
my_aiocb.aio_sigevent.sigev_notify = SIGEV_THREAD;
my_aiocb.aio_sigevent.notify_function = aio_completion_handler;
my_aiocb.aio_sigevent.notify_attributes = NULL;
my_aiocb.aio_sigevent.sigev_value.sival_ptr = &my_aiocb;
...
ret = aio_read( &my_aiocb );
}
void aio_completion_handler( sigval_t sigval )
{
struct aiocb *req;
req = (struct aiocb *)sigval.sival_ptr;
/* Did the request complete? */
if (aio_error( req ) == 0) {
/* Request completed successfully, get the return status */
ret = aio_return( req );
}
return;
}
|
鍦ㄦ竻鍗?6 涓紝鍦ㄥ垱寤鴻嚜宸辯殑 aiocb
璇鋒眰涔嬪悗錛屾垜浠嬌鐢?SIGEV_THREAD
璇鋒眰浜嗕竴涓嚎紼嬪洖璋冨嚱鏁版潵浣滀負閫氱煡鏂規硶銆傜劧鍚庢垜浠皢鎸囧畾鐗瑰畾鐨勯氱煡澶勭悊紼嬪簭錛屽茍灝嗚浼犺緭鐨勪笂涓嬫枃鍔犺澆鍒板鐞嗙▼搴忎腑錛堝湪榪欑鎯呭喌涓紝鏄釜瀵?aiocb
璇鋒眰鑷繁鐨勫紩鐢級銆傚湪榪欎釜澶勭悊紼嬪簭涓紝鎴戜滑綆鍗曞湴寮曠敤鍒拌揪鐨?sigval
鎸囬拡騫朵嬌鐢?AIO 鍑芥暟鏉ラ獙璇佽姹傚凡緇忓畬鎴愩?/p>
瀵?AIO 榪涜緋葷粺浼樺寲
proc 鏂囦歡緋葷粺鍖呭惈浜嗕袱涓櫄鎷熸枃浠訛紝瀹冧滑鍙互鐢ㄦ潵瀵瑰紓姝?I/O 鐨勬ц兘榪涜浼樺寲錛?/p>
- /proc/sys/fs/aio-nr 鏂囦歡鎻愪緵浜嗙郴緇熻寖鍥村紓姝?I/O 璇鋒眰鐜板湪鐨勬暟鐩?
- /proc/sys/fs/aio-max-nr 鏂囦歡鏄墍鍏佽鐨勫茍鍙戣姹傜殑鏈澶т釜鏁般傛渶澶т釜鏁伴氬父鏄?64KB錛岃繖瀵逛簬澶ч儴鍒嗗簲鐢ㄧ▼搴忔潵璇撮兘宸茬粡瓚沖浜嗐?
緇撴潫璇?
浣跨敤寮傛 I/O 鍙互甯姪鎴戜滑鏋勫緩 I/O 閫熷害鏇村揩銆佹晥鐜囨洿楂樼殑搴旂敤紼嬪簭銆傚鏋滄垜浠殑搴旂敤紼嬪簭鍙互瀵瑰鐞嗗拰 I/O 鎿嶄綔閲嶅彔榪涜錛岄偅涔?AIO 灝卞彲浠ュ府鍔╂垜浠瀯寤哄彲浠ユ洿楂樻晥鍦頒嬌鐢ㄥ彲鐢?CPU 璧勬簮鐨勫簲鐢ㄧ▼搴忋傚敖綆¤繖縐?I/O 妯″瀷涓庡湪澶ч儴鍒?Linux 搴旂敤紼嬪簭涓嬌鐢ㄧ殑浼犵粺闃誨妯″紡閮戒笉鍚岋紝浣嗘槸寮傛閫氱煡妯″瀷鍦ㄦ蹇典笂鏉ヨ鍗撮潪甯哥畝鍗曪紝鍙互綆鍖栨垜浠殑璁捐銆?
鍙傝冭祫鏂?
瀛︿範
鑾峰緱浜у搧鍜屾妧鏈?/strong>
- 璁㈣喘鍏嶈垂鐨?SEK for Linux錛岃繖鏈変袱寮?DVD錛屽寘鎷渶鏂扮殑 IBM for Linux 鐨勮瘯鐢ㄨ蔣浠訛紝鍖呮嫭 DB2®銆丩otus®銆丷ational®銆乀ivoli® 鍜?WebSphere®銆?
- 鍦ㄦ偍鐨勪笅涓涓紑鍙戦」鐩腑閲囩敤 IBM 璇曠敤杞歡錛岃繖鍙互浠?developerWorks 涓婄洿鎺ヤ笅杞姐?
璁ㄨ
鍏充簬浣滆?/span>
 |

|
 |
Tim Jones 鏄竴鍚嶅祵鍏ュ紡杞歡宸ョ▼甯堬紝浠栨槸 GNU/Linux Application Programming銆?em>AI Application Programming 浠ュ強 BSD Sockets Programming from a Multilanguage Perspective 絳変功鐨勪綔鑰呫備粬鐨勫伐紼嬭儗鏅潪甯稿箍娉涳紝浠庡悓姝ュ畤瀹欓鑸圭殑鍐呮牳寮鍙戝埌宓屽叆寮忔灦鏋勮璁★紝鍐嶅埌緗戠粶鍗?/p>
|