QNX之編寫資源管理器(五)

QNX相關(guān)歷史文章:

Combine Messages

這篇文章主要描述消息組合機(jī)制。

1. Where combine messages are used

消息組合機(jī)制,可以節(jié)省網(wǎng)絡(luò)帶寬,并支持原子操作。消息組合由客戶端的C庫(kù)來(lái)組建,由多個(gè)I/O消息和連接消息打包在一起組成。下邊來(lái)看看它的使用。

1.1 Atomic operations

考慮這么一種情況,當(dāng)兩個(gè)線程執(zhí)行以下代碼,讀取同一個(gè)文件描述符:

a_thread ()
{
    char buf [BUFSIZ];

    lseek (fd, position, SEEK_SET);
    read (fd, buf, BUFSIZ);
    …
}

當(dāng)?shù)谝粋€(gè)線程執(zhí)行lseek()時(shí),被第二個(gè)線程搶占,當(dāng)?shù)谝粋€(gè)線程恢復(fù)執(zhí)行時(shí),文件的偏移值已經(jīng)被修改了,有三種方法可以解決這個(gè)問(wèn)題:

  • 使用mutex互斥訪問(wèn)同一個(gè)文件描述符。使用mutex的問(wèn)題在于,每次讀寫操作等都需要加鎖,如果線程沒(méi)有按照約定執(zhí)行的話,還是可能會(huì)存在一樣的問(wèn)題;
  • 每個(gè)線程分別打開這個(gè)文件,維護(hù)兩個(gè)文件描述符。這是一種通用的好的解決方法;
  • 這兩個(gè)線程可以使用readblock()函數(shù),這個(gè)函數(shù)會(huì)原子的執(zhí)行lseek()read()。通過(guò)將_IO_LSEEK_IO_READ組合成一個(gè)消息,可以執(zhí)行原子的操作;

1.2 Bandwidth considerations

另外一個(gè)有用的地方就是stat()函數(shù),這個(gè)函數(shù)相當(dāng)于順序調(diào)用open()、fstat()close()三個(gè)函數(shù),可以將這三個(gè)函數(shù)對(duì)應(yīng)的消息組合成一個(gè)。這樣的操作可以提高效率,尤其在網(wǎng)絡(luò)連接中,此外也簡(jiǎn)化了資源管理器,因?yàn)榭梢圆槐厥褂眠B接函數(shù)來(lái)處理stat()。

2. The library's combine-message handling

資源管理器在處理消息組合的時(shí)候,會(huì)將消息傳遞給不同的處理函數(shù),比如當(dāng)_IO_LSEEK_IO_READ組合時(shí),資源管理器庫(kù)會(huì)調(diào)用io_lseek()io_read()來(lái)處理。
當(dāng)有多個(gè)線程發(fā)送組合的消息時(shí),那么就會(huì)出現(xiàn)同步的問(wèn)題,解決方法就是資源管理器庫(kù)提供了鎖住OCB的機(jī)制來(lái)互斥訪問(wèn),比如處理readblock()消息組合時(shí),可以按以下方式處理:

  • lock_ocb handler
  • _IO_LSEEK message handler
  • _IO_READ message handler
  • unlock_ocb handler

看看幾個(gè)與消息組合相關(guān)的問(wèn)題:

2.1 Component responses

消息組合就是將常規(guī)的資源管理器消息組合成一個(gè)消息,資源管理器在收到組合的消息后再進(jìn)行拆解并調(diào)用對(duì)應(yīng)的處理函數(shù)處理。通常這樣不會(huì)帶來(lái)額外的處理,但有一個(gè)case是例外:readblock()
通常,在處理完_IO_LSEEK消息后,處理程序?qū)⒎祷匚募漠?dāng)前位置,但是下一條消息_IO_READ也返回?cái)?shù)據(jù),按照約定,只有組合消息中的最后一個(gè)消息才返回?cái)?shù)據(jù),中間消息只允許返回通過(guò)/失敗的指示。因此在lseek()中需要去判斷是否在組合消息中,代碼如下:

int
iofunc_lseek_default (resmgr_context_t *ctp,
                      io_lseek_t *msg,
                      iofunc_ocb_t *ocb)
{
    /* 
     *  performs the lseek processing here
     *  may "early-out" on error conditions
     */
     . . .

    /* decision re: combine messages done here */
    if (msg -> i.combine_len & _IO_COMBINE_FLAG) {
        return (EOK);
    }

    msg -> o = offset;
    return (_RESMGR_PTR (ctp, &msg -> o, sizeof (msg -> o)));
}

如果在處理函數(shù)中返回的不是EOK,則組合消息的處理會(huì)被中止,并將狀態(tài)發(fā)送給客戶端。

2.2 Component data access

第二個(gè)與消息組合相關(guān)的問(wèn)題是如何去訪問(wèn)后續(xù)消息組件的數(shù)據(jù)區(qū)域。比如writeblock()需要處理的消息就包括:_IO_SEEK, _IO_WRITE, data三部分,其中數(shù)據(jù)也是以消息的形式來(lái)傳送。資源管理器提供了resmgr_msgread()函數(shù),用于獲取與消息組件對(duì)應(yīng)的數(shù)據(jù),因此在io_write()處理函數(shù)中,應(yīng)該使用resmgr_msgread()替換MsgRead()。實(shí)際上,資源管理器應(yīng)該始終都使用resmgr_msgread()函數(shù),它的實(shí)現(xiàn)如下:

int resmgr_msgread( resmgr_context_t *ctp,
                    void *msg,
                    int nbytes,
                    int offset)
{
    return MsgRead(ctp->rcvid, msg, nbytes, ctp->offset + offset);
}

對(duì)應(yīng)的還提供了一個(gè)`resmgr_msgwrite()·函數(shù)。

2.3 Locking and unlocking the attribute structure

對(duì)屬性結(jié)構(gòu)需要互斥訪問(wèn),屬性結(jié)構(gòu)存放在OCB中,提供了加鎖的機(jī)制:

  • lock_ocb
  • unlock_ocb
    比如在訪問(wèn)屬性結(jié)構(gòu)的時(shí)候,可以使用iofunc_attr_lock()iofunc_attr_unlock()。

2.4 Connect message types

可以看看一般的case:io_open處理程序,并不總是對(duì)應(yīng)于客戶端的open()調(diào)用,比如客戶端可能調(diào)用stat()access()。

  • _IO_CONNECT_COMBINE_CLOSE
    當(dāng)調(diào)用stat()函數(shù)時(shí),相當(dāng)于順序執(zhí)行open()/fstat()/close(),進(jìn)行消息組合后可以提高效率,包括消息:
    _IO_CONNECT_COMBINE_CLOSE, _IO_STAT,對(duì)應(yīng)執(zhí)行的操作:io_open, io_lock_ocb, io_stat, io_unlock_ocb,io_close。_IO_CONNECT_COMBINE_CLOSE消息會(huì)調(diào)用io_open處理函數(shù),同時(shí)也會(huì)隱式調(diào)用io_close_ocb處理函數(shù)。

  • _IO_CONNECT_COMBINE
    當(dāng)客戶端調(diào)用access()接口時(shí),C庫(kù)底層會(huì)去執(zhí)行stat()調(diào)用,并根據(jù)stat()調(diào)用的結(jié)果,可選的執(zhí)行devctl()來(lái)獲取更多信息,最后還需要調(diào)用close()來(lái)關(guān)閉設(shè)備。
    包括消息:_IO_CONNECT_COMBINE, _IO_STAT, _IO_DEVCTL(optional), _IO_CLOSE;涉及的操作有:io_open, io_lock_ocb, io_stat, io_unlock_ocb, io_lock_ocb (optional), io_devctl (optional), io_unlock_ocb (optional), io_close。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容