<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                根據前文分析可知,Surface系統中的CB,其實是指SharedBuffer家族,它們是Surface系統中對生產者和消費者進行步調控制的中樞機構。先通過圖8-24來觀察整體的工作流程是怎樣的。 :-: ![](http://img.blog.csdn.net/20150802163013569?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-24 SharedBuffer家族使用流程 為書寫方便起見,我們簡稱: - SharedBufferServer為SBS。 - SharedBufferClient為SBC。 - SharedBufferStack為SBT。 其中SBC和SBS都是建立在同一個SBT上的,所以應先看SBT,下面代碼列出了其中幾個與讀寫控制有關的成員變量: **SharedBufferStack.h** ~~~ class SharedBufferStack{ ...... /* 雖然PageFlipping使用Front和Back兩個Buffer就可以了,但是SBT的結構和相關算法 是支持多個緩沖的。另外,緩沖是按照塊來獲取的,也就是一次獲得一塊緩沖,每塊緩沖用 一個編號表示(這一點在之前的分析已經介紹過了)。 */ int32_t head; int32_tavailable; //當前可用的空閑緩沖個數 int32_t queued; //SBC投遞的臟緩沖個數 int32_tinUse; //SBS當前正在使用的緩沖編號 ......//上面這幾個參數聯合SBC中的tail,我稱之為控制參數。 } ~~~ SBT創建好后,下面就是SBS和SBC的創建了,它們會做什么特殊工作嗎? 1. SBS和SBC的創建 下面分別看SBS和SBC的創建,代碼如下所示: **SharedBufferStack.cpp** ~~~ SharedBufferServer::SharedBufferServer(SharedClient*sharedClient, int surface, int num, int32_t identity) :SharedBufferBase(sharedClient, surface, num, identity) { mSharedStack->init(identity);//這個函數將設置inUse為-1 //下面設置SBT中的參數,我們關注前三個 mSharedStack->head = num-1; mSharedStack->available = num; mSharedStack->queued = 0; //設置完后,head=2-1=1,available=2,queued=0,inUse=-1 mSharedStack->reallocMask = 0; memset(mSharedStack->dirtyRegion, 0,sizeof(mSharedStack->dirtyRegion)); } ~~~ 再看SBC的創建,代碼如下所示: **SharedBufferStack.cpp** ~~~ SharedBufferClient::SharedBufferClient(SharedClient*sharedClient, int surface, int num, int32_t identity) :SharedBufferBase(sharedClient, surface, num, identity), tail(0) { tail =computeTail(); //tail是SBC定義的變量,注意它不是SBT定義的。 } ~~~ 看computeTail函數的代碼: **SharedBufferStack.cpp** ~~~ int32_t SharedBufferClient::computeTail() const { SharedBufferStack& stack( *mSharedStack ); int32_t newTail; int32_t avail; int32_t head; do { avail = stack.available; //available=2,head=1 head = stack.head; }while (stack.available != avail); newTail = head - avail + 1;//newTail=1-2+1=0 if(newTail < 0) { newTail += mNumBuffers; } elseif (newTail >= mNumBuffers) { newTail -= mNumBuffers; } return newTail;//計算得到newTail=0 } ~~~ 來看在SBC和SBS創建后,控制參數的變化,如圖8-25所示: :-: ![](http://img.blog.csdn.net/20150802163038607?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-25 SBC/SBS創建后的示意圖 2. SBC端流程的分析 下面看SBC端的工作流程。 (1)dequeue分析 先看SBC的dequeue函數: **SharedBufferStack.cpp** ~~~ ssize_t SharedBufferClient::dequeue() { SharedBufferStack& stack( *mSharedStack ); ...... //DequeueCondition函數對象 DequeueCondition condition(this); status_t err = waitForCondition(condition); //成功以后,available減1,表示當前可用的空閑buffer只有1個 if (android_atomic_dec(&stack.available) == 0) { ...... } int dequeued = tail; //tail值為0,所以dequeued的值為0。 //tail加1。如果超過2,則重新置為0,這表明tail的值在0,1間循環。 tail =((tail+1 >= mNumBuffers) ? 0 : tail+1); ...... //返回的這個dequeued值為零,也就是tail加1操作前的舊值。這一點請讀者務必注意。 returndequeued; } ~~~ 其中DequeueCondition的操作函數很簡單,代碼如下所示: ~~~ bool SharedBufferClient::DequeueCondition::operator()(){ returnstack.available > 0;//只要available大于0就算滿足條件,第一次進來肯定滿足 } ~~~ 用圖8-26來表示dequeue的結果: :-: ![](http://img.blog.csdn.net/20150802163105267?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-26 dequeue結果圖 注意,在上圖中,0號緩沖用虛線表示,SBC的dequeue函數的返回值用dequeued表示,它指向這個0號緩沖。正如代碼中注釋的那樣,由于dequeued的值用的是tail的舊值,而tail是SBC定義的變量,不是SBT定義的變量,所以tail在SBS端是不可見的。這就帶來了一個潛在危險,即0號緩沖不能保證當前是真正空閑的,因為SBS可能正在用它,怎么辦?試看下面的lock。 (2)lock的分析 lock使用了LockCondition,其中傳入的參數buf的值為0,也就是上圖中的dequeue的值,代碼如下所示: **SharedBufferStack.cpp** ~~~ status_t SharedBufferClient::lock(int buf) { LockCondition condition(this, buf); status_terr = waitForCondition(condition); returnerr; } ~~~ 看LockCondition的()函數: ~~~ boolSharedBufferClient::LockCondition::operator()() { /* 這個條件其實就是判斷編號為buf的Buffer是不是被使用了。 buf值為0,head值為1,queued為0,inUse為-1 */ return(buf != stack.head || (stack.queued > 0 && stack.inUse!= buf)); } ~~~ 現在可以知道為什么SBC需要調用dequeue和lock函數了嗎?原來: - dequeue只是根據本地變量tail計算一個本次應當使用的Buffer編號,其實也就是在0,1之間循環。上次用0號緩沖,那么這次就用1號緩沖。 - lock函數要確保這個編號的Buffer沒有被SF當做FrontBuffer使用。 (3)queue的分析 Activity端在繪制完UI后,將把BackBuffer投遞出去以顯示。接著上面的流程,這個BackBuffer的編號是0。待Activity投遞完后,才會調用signal函數觸發SF消費,所以在此之前格局不會發生變化。試看投遞用的queue函數,注意傳入的buf參數為0,代碼如下所示: **SharedBufferStack.cpp** ~~~ status_t SharedBufferClient::queue(int buf) { QueueUpdate update(this); status_t err = updateCondition( update ); ...... returnerr; } //直接看這個QueueUpdate函數對象 ssize_tSharedBufferClient::QueueUpdate::operator()() { android_atomic_inc(&stack.queued);//queued增加1,現在該值由零變為1 returnNO_ERROR; } ~~~ 至此,SBC端走完一個流程了,結果是什么?如圖8-27所示: :-: ![](http://img.blog.csdn.net/20150802163251975?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-27 queue結果圖 0號緩沖被移到queue的區域了,可目前還沒有變量指向它。假設SBC端此后沒有繪制UI的需求,那么它就會沉默一段時間。 3. SBS端的分析 SBS的第一個函數是retireAndLock,它使用了RetireUpdate函數對象,代碼如下所示: **SharedBufferStack.cpp** ~~~ ssize_t SharedBufferServer::retireAndLock() { RetireUpdate update(this, mNumBuffers); ssize_t buf = updateCondition( update ); returnbuf; } ~~~ 這個RetireUpdate對象的代碼如下所示: ~~~ ssize_tSharedBufferServer::RetireUpdate::operator()() { //先取得head值,為1 int32_t head = stack.head; //inUse被設置為1。表明要使用1嗎?目前的臟緩沖應該是0才對 android_atomic_write(head, &stack.inUse); int32_tqueued; do { queued = stack.queued; //queued目前為1 if(queued == 0) { return NOT_ENOUGH_DATA; } //下面這個原子操作使得stack.queued減1. }while (android_atomic_cmpxchg(queued, queued-1, &stack.queued)); //while循環退出后,queued減1,又變為0。 //head值也在0,1間循環,現在head值變為0了 head =((head+1 >= numBuffers) ? 0 : head+1); //inUse被設置為0 android_atomic_write(head, &stack.inUse); // head值被設為0 android_atomic_write(head, &stack.head); // available加1,變成2. android_atomic_inc(&stack.available); returnhead;//返回0 } ~~~ retireAndLock的結果是什么呢?看看圖8-28就知道了。 :-: ![](http://img.blog.csdn.net/20150802163200023?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-28 retireAndLock結果圖 注意上面的available區域,1號緩沖右邊的0號緩沖是用虛線表示的,這表示該0號緩沖實際上并不存在于available區域,但available的個數卻變成2了。這樣不會出錯嗎?當然不會,因為SBC的lock函數要確保這個緩沖沒有被SBS使用。 我們來看SBS端最后一個函數,它調用了SBS的unlock,這個unlock使用了UnlockUpdate函數對象,就直接了解它好了,代碼如下所示: **SharedBufferStack.cpp** ~~~ ssize_tSharedBufferServer::UnlockUpdate::operator()() { ...... android_atomic_write(-1, &stack.inUse);//inUse被設置為-1 returnNO_ERROR; } ~~~ unlock后最終的結果是什么呢?如圖8-29所示: :-: ![](http://img.blog.csdn.net/20150802163326841?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖8-29 unlock結果圖 比較一下圖8-29和圖8-25,可能會發現兩圖中tail和head剛好反了,這就是PageFlip。另外,上面的函數大量使用了原子操作。原子操作的目的就是為了避免鎖的使用。值得指出的是,updateConditon函數和waitForCondition函數都使用了Mutex,也就是說,上面這些函數對象又都是在Mutex鎖的保護下執行的,為什么會這樣呢?先來看一段代碼: ~~~ 像下面這樣的代碼,如果有鎖控制的話根本用不著一個while循環,因為有鎖的保護,沒有其他線程 能夠修改stack.queued的值,所以用while來循環判斷android_atomic_cmpxchg沒有什么意義。 int32_tqueued; do { queued = stack.queued; if(queued == 0) { return NOT_ENOUGH_DATA; } }while (android_atomic_cmpxchg(queued, queued-1, &stack.queued)); ~~~ 對于上面這個問題,我目前還不知道答案,但對其也進行了修改,把函數對象放在鎖外執行,結果在真機上運行沒有出現任何異常現象。也許Google或哪位讀者能給這個問題一個較好的解釋。 為什么我對生產/消費的同步控制如此感興趣呢?這和自己工作的經歷有些關系。因為之前曾做過一個單寫多讀的跨進程緩沖類,也就是一個生產者,多個消費者。為了保證正確性和一定的效率,我們在算法上曾做了很多改進,但還是大量使用了鎖,所以我很好奇Google是怎么做到的,這也體現了一個高手的內功修養。要是由讀者自己來實現,結果會怎樣呢?
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看