青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

martin

thinking

常用鏈接

統(tǒng)計

software

最新評論

2013年7月8日 #

Linux操作系統(tǒng)中中斷上下文中的互斥

在Linux系統(tǒng)中,有兩種不同的上下文:進程上下文、中斷上下文。
在中斷中沒有進程上下文,而具有中斷上下文,因此在中斷上下文中不能發(fā)生睡眠,也就是不能發(fā)生進程切換。
這就決定了在在中斷上下文中不能采用同步原語(信號量,管程、同步變量等)和長期互斥原語(這會導(dǎo)致進程睡眠), 而只能采用短期互斥原語(例如自旋鎖)。

曾經(jīng),中斷處理程序并不具有自己的棧。相反,它們共享所中斷進程的內(nèi)核棧。內(nèi)核棧的大小是兩頁,具體地說,在32位體系結(jié)構(gòu)上是8KB,在64位體系結(jié)構(gòu)上是16KB.
現(xiàn)在。中斷處理程序有了自己的棧,每個處理器一個,大小為一頁。這個棧就稱為中斷棧,盡管中斷棧的大小是原先共享棧的一半,但平均可用棧空間大得多,因為中斷處理
程序把這一整頁占為己有。

UP(單CPU系統(tǒng))上的中斷處理
互斥
如果一個中斷處理程序的代碼訪問或者更新了由非中斷的代碼(通常稱為基準代碼)使用的同一數(shù)據(jù)結(jié)構(gòu),那么就會出現(xiàn)競爭條件。
幸運的是,得到允許的以內(nèi)核態(tài)執(zhí)行的進程會臨時禁止中斷。因此,只要基準代碼要更新一個與中斷處理程序共享的數(shù)據(jù)結(jié)構(gòu),那么就
首先禁止中斷,執(zhí)行臨界段,然后再重新允許中斷。禁止和允許中斷的動作就實現(xiàn)了互斥。
在采取中斷互斥時,必須使用函數(shù)顯示地把編碼寫入算法中。

MP(多CPU系統(tǒng))上
在MP系統(tǒng)上,中斷可以在任何處理器上出現(xiàn)。從最低限度上來說,每個進程會接收時鐘中斷,但也可能接收I/O中斷。在MP系統(tǒng)上,例程
SPL(禁止中斷)所提供的保護并不充分,因為它們執(zhí)行影響執(zhí)行它們的處理器上的中斷優(yōu)先級。中斷可能會在另一個處理器上出現(xiàn),如果設(shè)備驅(qū)動程序
正在別處運行,那么會造成一個競爭條件。因為中斷處理程序代表另一個進入內(nèi)核的入口點。

當基準驅(qū)動程序代碼和中斷處理程序之間共享數(shù)據(jù)結(jié)構(gòu)時,UP可以通過屏蔽中斷來防止出現(xiàn)競爭條件的技術(shù),在多線程MP內(nèi)核中還不充分。
臨界段要在一個處理器上執(zhí)行,執(zhí)行屏蔽中斷例程只會屏蔽在那個處理器上出現(xiàn)的中斷。如果在別的處理器上出現(xiàn)中斷,那么立即就會有
兩個處理器同時訪問、而且可能更新臨界資源。既然這些臨界段需要短期互斥,那么可以使用自旋鎖來對數(shù)據(jù)進行保護。

如果不考慮中斷處理程序和基準代碼之間的互斥,則Linux中的中斷處理程序是無須重入的。當一個給定的中斷處理程序正在執(zhí)行時,相應(yīng)的中斷線
在所有處理器上都會被屏蔽掉,以防止同一中斷線上接收另一個新的中斷。通常情況下,所有的其他中斷都是打開的,所以這些不同中斷線上的其他中斷
都能處理,但當前中斷線總是被禁止的。由此可以看出,同一個中斷處理程序絕不會被同時調(diào)用以處理嵌套的中斷。這極大地簡化了中斷程序的編寫。

posted @ 2013-07-08 14:01 martin_yahoo 閱讀(3448) | 評論 (0)編輯 收藏

2013年6月20日 #

unix 類系統(tǒng)中的進程同步方式代碼示例

MP(多CPU)同步原語代碼示例
                   ----引自《現(xiàn)代體系結(jié)構(gòu)上的UNIX系統(tǒng)》

為了便于對示例的展開,我們首先假定一個場景:
內(nèi)核中把檢測到的錯誤信息記錄到一個磁盤文件中的情形。出錯信息通過內(nèi)存中的一個隊列來傳遞給日志進程(logging process)的。
當出現(xiàn)一個錯誤時,就在隊列中加入一項,并且通過調(diào)用函數(shù)log_error 通知日志進程。出錯日志進程接著把隊列中的項寫到磁盤上。
這就使得碰到錯誤的進程不必等候I/O完成或者或得為了向文件執(zhí)行I/O而可能需要的任何鎖,并且避免了任何可能的上鎖次序問題。

代碼1, 采用事件計數(shù)的出錯日志通知機制

                                                日志進程
log_error(error)                    |
{                                         |       for(next=1; ; next++) {
    lock(&err_queue);             |           await(&err_event, next);
    把出錯信息加入到隊列           |          lock(&err_queue);
    unlock(&err_queue);          |          從隊列中刪除項
    advance(&err_event);        |          unlock(&err_queue);
}                                         |          write error to disk
                                           |       }

隊列本身由一個自旋鎖來保護。在本例中,事件計數(shù)只用于同步的目的,并不提供互斥。
在試用事件計數(shù)的時候,advance操作會永久性地改變事件計數(shù)的狀態(tài)。advance和await操作的相對時序沒有關(guān)系。

代碼2, 采用同步變量的出錯日志通知機制
                                                 日志進程
log_error(error)                            |
{                                                 |        for(;;){
   lock(&err_queue);                      |              lock(&err_queue);
   把出錯信息加入到隊列                    |              if (queue_empty){
   SV_SIGNAL(&err_syncvar, 0);      |                  SV_WAIT(&err_syncvar, PRI, &err_queue);
   unlock(&err_queue);                   |                  lock(&err_queue);
}                                                 |              }
                                                   |              從隊列中刪除項
                                                   |              unlock(&err_queue);
                                                   |              把錯誤寫入磁盤
                                                   |        }

因為同步變量自身沒有保留狀態(tài),所以當日志進程測試隊列的狀態(tài)并決定是等待一項還是從隊列中刪除一項的時候,必須占有自旋鎖。類似地,log_error在
發(fā)送信號時也必須占有自旋鎖。注,SV_WAIT將釋放自旋鎖,并且阻塞日志進程,SV_SIGNAL到后從阻塞處繼續(xù)執(zhí)行。

代碼3, 采用管程的出錯日志通知機制
                                                                 日志進程
log_error(error)                                  |       for(;;){
{                                                       |           mon_enter(&err_mon);
   mon_enter(&err_mon);                     |           if (queue empty)
   把出錯信息加入到隊列                          |               mon_wait(&err_mon, NEWENTRY);
                                                         |
   mon_signal(&err_mon, NEWENTRY);  |           從隊列中刪除項
   mon_exit(&err_mon);                       |           mon_exit(&err_mon);
}                                                       |           把錯誤寫入磁盤
                                                         |       }
                                    
代碼4, 采用信號量的出錯日志通知機制
                                                日志進程
log_error(error)                      |       for(;;){
{                                          |           P(&err_sema);
    lock(&err_queue);               |           lock(&err_queue);
    把出錯信息加入到隊列            |           從隊列中刪除項
    unlock(err_queue);              |           unlock(&err_queue);
    V(&err_sema);                   |           把錯誤寫入磁盤
}                                          |       }

posted @ 2013-06-20 15:02 martin_yahoo 閱讀(1564) | 評論 (0)編輯 收藏

unix 類系統(tǒng)中的進程同步方式總結(jié)

我們把異步環(huán)境下的一組并發(fā)進程因直接制約而互相發(fā)送消息、進行互相合作、互相等待,使得各進程按一定的速度執(zhí)行的過程稱為進程間的同步。
具有同步關(guān)系的一組并發(fā)進程稱為合作進程,合作進程間互相發(fā)送的信號稱為消息或事件。 如果我們對一個消息或事件賦以唯一的消息名,則我們
可用過程 wait (消息名)  表示進程等待合作進程發(fā)來的消息,而用過程 signal (消息名) 表示向合作進程發(fā)送消息。
(引自百度百科)

進程間的同步方式:
為了實現(xiàn)進程互斥地進入自己的臨界區(qū),操作系統(tǒng)中設(shè)置專門的同步機制來協(xié)調(diào)各進程間的運行。所有的同步機制都應(yīng)遵循下書四條準則:
1)空閑讓進
2)忙則等待
3)有限等待
4)讓權(quán)原則。當進程不能進入自己的臨界區(qū)時,應(yīng)立即釋放處理機,以免進程陷入“忙等”狀態(tài)。

1.單CPU (UP)機器利用sleep/wakeup函數(shù)對實現(xiàn)同步機制。
函數(shù)sleep是一個內(nèi)部的內(nèi)核例程,它掛起調(diào)用它的進程,直到指定的事件發(fā)生為止。這是一個以內(nèi)核態(tài)運行的進程自愿出讓控制權(quán),允許自己被搶占。
函數(shù)wakeup用于發(fā)出一個特定事件已經(jīng)出現(xiàn)的信號,它使得所有等待該事件的進程被喚醒,并放回到運行隊列中。事件用一個整數(shù)值來表示,它往往
是該事件相關(guān)的內(nèi)核數(shù)據(jù)結(jié)構(gòu)的地址。

void lock_object( char *flag_ptr)
{
    lock(&object_locking);        //自旋鎖
     while (*flag_ptr)
           sleep(flag_ptr);
     *flag_ptr = 1;
    unlock(&object_locking);
}

void unlock_object( char *flag_ptr)
{
    lock( &object_locking );
    *flag_ptr = 0;
    wakeup( flag_ptr);
    unlock( &object_locking );
}

應(yīng)為wakeup操作沒有記憶,所以wakeup函數(shù)必須喚醒在同一事件上睡眠的所有進程。在多CPU系統(tǒng)上,即MP上sleep/wakeup機制不起作用。

2.SVR4.2 MP 提供了單獨的執(zhí)行進程同步的原語:同步變量。
因為同步變量不包含狀態(tài),所以可以把它們想成是sleep/wakeup的一種MP變形。相反,所需的任何狀態(tài)信息都保存在外部標志或者計數(shù)器中。
同步變量的設(shè)計要同自旋鎖配合工作。

同步變量被聲明為sv_t類型,采用下面的函數(shù)可以給它分配空間和進行初始化:
sv_t *SV_ALLOC( int slpflag);
slpflag指定,如果需要為同步變量分配內(nèi)存,那么是否能阻塞進程。

回收同步變量可以調(diào)用
void SV_DEALLOC( sv_t *svp );

內(nèi)核希望單獨等候的每一個事件都用一個不同的同步變量來表示,這就好比配合sleep如何使用唯一的事件參數(shù)。
void SV_WAIT( sv_t *svp, int pri, lock_t *lockp );

要觸發(fā)在同步變量上的事件,可以使用下面的函數(shù):
void SV_SIGNAL( sv_t *svp, int flags);
SV_SIGNAL與wakeup的相似之處在于,如果沒有正在睡眠的進程,那么就對過去曾經(jīng)執(zhí)行過的操作沒有記憶,調(diào)用什么也不做。
SV_SIGNAL只喚醒一個進程。如果要喚醒在事件上睡眠的所有進程,可以用同步變量的下列函數(shù)來實現(xiàn):
void SV_BROADCAST( sv_t *svp, int flags);

如果在事件被觸發(fā)之前出現(xiàn)了一個UNIX信號,那么下面的SV_WAIT變形會喚醒進程:
bool_t SV_WAIT_SIG( sv_t *svp, int pri, lock_t *lkp );
返回的代碼表明發(fā)生了什么樣的事件:如果出現(xiàn)了一個UNIX信號,那么它返回FALSE,如果出現(xiàn)了SV_SIGNAL或SV_BROADCAST,那么它返回TRUE.

3.采用信號量的同步
將信號量的值初始化為0,就可以用于進程同步,這樣允許通過使用P操作讓一個進程等待某個事件發(fā)生。既然信號量被初始化為0,那么進程將立即阻塞。
另一個進程使用V操作能夠發(fā)出信號,表明事件已經(jīng)結(jié)束。V操作導(dǎo)致正等待事件的進程被喚醒,并繼續(xù)進行。因為即使在信號量上沒有阻塞進程,
V操作也會給信號量加1,所以在前一個進程能夠執(zhí)行P操作之前出發(fā)事件會導(dǎo)致進程繼續(xù)進行,不必等待。這是一種受歡迎的情形,因為它不需要額外的
協(xié)調(diào)工作,就能夠處理在等候事件的進程同發(fā)信號表明該事件完成的進程之間本來就有的競爭條件。

進程1                                        進程2
p(s)       /*等待事件*/                    .
                                                  .
                                                  .
                                                V(s) /*觸發(fā)事件*/


4.利用管程進行同步
管程為臨界資源以及訪問或者修改該資源的所有臨界段提供了互斥機制,它還提供了在使用管程的諸進程之間進行同步的手段。一個管程可以想成是一個裝有
資源的隔間。進程要訪問資源,它必須首先進入隔間。通過一次只允許一個進程進入隔間,就做到了互斥。如果在管程已經(jīng)投入使用的時候,別的進程試圖進
入它,那就會被阻塞,直到使用管程的進程退出管程為止,或者在與管程關(guān)聯(lián)的事件上等待。每個管程都可能有一個或者更多的事件,若干進程能夠在這些事
件上等待。進程被阻塞這些事件上,直到在管程內(nèi)執(zhí)行的其他進程觸發(fā)事件為止。根據(jù)定義,觸發(fā)操作只能從管程內(nèi)部完成。


5.利用事件計數(shù)進行同步
事件計數(shù)是一個非遞減的正整數(shù),在這個數(shù)值上定義了3種操作。操作advance(E)將事件計數(shù)E加1,這叫做出發(fā)事件。
操作await(E,V)致使調(diào)用進程被阻塞,指導(dǎo)事件計數(shù)E的值達到V為止。如果在調(diào)用await的時候,事件計數(shù)的值大于或等于V,那么進程繼續(xù)執(zhí)行,而不會阻塞,
因為事件是以前觸發(fā)的。事件計數(shù)的當前值可以用read(E)來讀取。在創(chuàng)建事件計數(shù)的時候,它被初始化為0,而且在數(shù)值上永遠不會減少。假定保存事件計數(shù)值
得存儲器位置足夠大,于是事件計數(shù)在其整個生命期中,一直都不會溢出(通常一個32位的無符號整數(shù)就夠了)。

有關(guān)代碼示例,請參見后面的隨筆。

posted @ 2013-06-20 13:49 martin_yahoo 閱讀(2188) | 評論 (2)編輯 收藏

2013年6月8日 #

MP操作系統(tǒng)內(nèi)核中自旋鎖(spinlock)的實現(xiàn)

在多CPU系統(tǒng),即MP系統(tǒng)中,存在總線仲裁。

1. 原子操作
從CPU或者I/O設(shè)備到主存儲器的單次讀或者寫操作為原子操作。
這樣的操作一旦開始,就不能被系統(tǒng)上來自CPU或者I/O設(shè)備的任何其他存儲操作所中斷,或者受到他們的干擾。

原子變量

2. 自旋鎖 (自旋鎖用于短期互斥)
自旋鎖得名于這樣一個事實,一個進程在等候另一個進程正在使用的鎖時會處于忙等待(busy-wait,在一個循環(huán)中自旋)狀態(tài)。
typedef int lock_t;
void initlock( volatile lock_t * lock_status)
{
   *lock_status = 0;
}

int
test_and_set(volatile int *addr)
{
     int old_value;
     old_value = swap_atomic(addr, 1);
     if (old_value == 0)
          return 0;
     return 1;
}

void lock(volatile lock_t *lock_status)
{
    while (test_and_set( lock_status) == 1)            //被鎖定時,進程在此自旋。
       ;
 }
// test_and_set 如果前面的狀態(tài)不為0就返回1,否則返回0.
//如果鎖的狀態(tài)已經(jīng)是1(鎖已經(jīng)被占用),那么test_and_set函數(shù)返回1,并且處理器在循環(huán)中自旋,直到該鎖被釋放為止。只要把鎖的狀態(tài)設(shè)置為0,就可以釋放鎖了。

void
unlock(volatile lock_t * lock_status)
{
   *lock_status =0;
}

減少對鎖的爭用可以采用兩種辦法:
第一、內(nèi)核針對不同的臨界資源使用不同的自旋鎖,防止處理器在沒有競爭條件威脅的時候被另一個處理器掛起。
第二、增強lock和unlock函數(shù),在上鎖的時候屏蔽中斷。

posted @ 2013-06-08 17:04 martin_yahoo 閱讀(1772) | 評論 (1)編輯 收藏

如何避免在應(yīng)用中可能出現(xiàn)的死鎖

在平時的應(yīng)用設(shè)計中,由于出現(xiàn)多線程(進程)的并發(fā)應(yīng)用,以及分布式應(yīng)用,比較容易出現(xiàn)死鎖現(xiàn)象。

下面來看一個簡單的實例:
有兩個獨立的鏈表,假定使用兩個獨立的鎖來保護他們,以便能夠獨立的訪問。再假定某個操作要求遍歷一個列表所檢索到的元素必須從兩個列表中斷開連接,
而且必須以一次原子操作來完成。

線程1                                                   |           線程2
lock(&lock_a);                                      |        lock(&lock_b);
find element to unlink on list a               |        find element to unlink on list b
lock(&lock_b);                                      |        lock(&lock_a);
unlink element from both lists                |        unlink element from both lists
unlock(&lock_b);                                   |        unlock(&lock_a);
unlock(&lock_a);                                   |        unlock(&lock_b);

可能出現(xiàn)死鎖的情況。
這要求在消除一個元素是必須同時擁有兩個列表的鎖。對第一個線程要先或得鎖lock_a, 然后要或得鎖lock_b.
第2個線程正好相反,它先或得鎖lock_b,然后再獲取鎖lock_a.
如果某一時刻,第一個線程執(zhí)行到了 find element to unlink on list a, 而第二個線程此時執(zhí)行到了find element to unlink on list b, 則這兩個線程將發(fā)生死鎖。
這種死鎖稱為AB-BA死鎖。   (注,死鎖的發(fā)生是跟兩個線程的執(zhí)行時序相關(guān)的,例如,第一個線程執(zhí)行完了所有的這部分代碼,線程2才開始執(zhí)行此段代碼,則不會發(fā)生死鎖。)

如果某個鎖不是遞歸鎖,例如lock_a, 而線程1在應(yīng)用中對它進行多個調(diào)用,而沒有調(diào)用解鎖操作,也會發(fā)生死鎖。
代碼示例如下:
lock(&lock_a);
other logic code
lock(&lock_a);
other logic code
unlock(&lock_a);
unlock(&lock_a);

防止死鎖的辦法: 為了防止發(fā)生這類死鎖,所有線程必須以相同的次序獲得嵌套鎖,即以相同的次序獲得且同時占有鎖。
可以把上面的代碼改成如下代碼來避免死鎖:
lock(&lock_a);
lock(&lock_b);
find element to unlink on list a or b
unlink element from both lists
unlock(&lock_b);
unlock(&lock_a);

當涉及到3個或者更多鎖的時候也是如此:只要各線程在獲得和釋放鎖的時候保持相同的次序,那么就不會出現(xiàn)死鎖。

posted @ 2013-06-08 14:54 martin_yahoo 閱讀(2000) | 評論 (2)編輯 收藏

2009年3月20日 #

應(yīng)用的擴展

實體(語言內(nèi)建的數(shù)據(jù)類型,開發(fā)者定義的類和方法等)的定義與聲明,實體和指針跟程序設(shè)計帶來了不同影響.
對于實體或定義,編譯器要知道實體真實的物理內(nèi)存布局,因此讓編譯器知道這些信息,并且在程序編譯完畢后不能更改.要想更改必須重新編譯程序.因此如果在系統(tǒng)設(shè)計者程序庫中運用了inline函數(shù),并且如果應(yīng)用開發(fā)者在應(yīng)用中用了這個inline函數(shù),則當后來要對inline進行修改時,有可能要導(dǎo)致應(yīng)用被重新編譯.
對于指針,它的大小在特定的機器上是固定的(在32位機器上,它的大小是32位;在64位機器上,它的大小是64位).因此可以改變它的值,而不需要重新編譯應(yīng)用,就可以改變應(yīng)用的功能.

在面向?qū)ο笾校梢酝ㄟ^虛函數(shù)指針來延遲特定函數(shù)的決策,即調(diào)用子類的函數(shù).
在C語言中,我們可以通過函數(shù)指針來對函數(shù)的功能進行推遲決策.
在C++中,我們也可以通過函數(shù)指針(函數(shù)對象)、對象指針來推遲決策,從而使程序的功能更有彈性。例如,在設(shè)計模式中的strategy模式中,就是通過在contex中包含一個指向strategy的指針來實現(xiàn)的。我們可以定義一個抽象的strategy接口,然后由各個具體的strategy實現(xiàn)這些接口,從而在保證應(yīng)用架構(gòu)幾乎不做任何調(diào)整下,實現(xiàn)不同的功能。當然在這種實現(xiàn)方式中,我們應(yīng)該加入strategy的決議者,由它來裁決采用哪一種策略方式。決議者可以采用配置文件、應(yīng)用的輸入等作為決議的依據(jù)。

熟悉symbian的人,很快就會發(fā)現(xiàn):它與symbian中的ECOM架構(gòu)很相似。它要求各種strategy的實現(xiàn)方式被包含在共享的DLL中,并由RLibrary::Loard()調(diào)用動態(tài)載入.
使用定義抽象接口,然后在各DLL中定義具體的實現(xiàn),并且動態(tài)載入,我們可以比較容易地實現(xiàn)所謂的插件(plugin)。插件的載入取決于配置,或相應(yīng)的輸入檢測。

下面給出在linux和windows上從動態(tài)庫中查找和載入的例子:
#ifdef WIN32
        HINSTANCE hDll;
        if(!(hDll = LoadLibrary(VOCALSIP_DLLPATH)))
        adapter.m_initFunc = (INIT_PROTOSTACK_FUNC)GetProcAddress( hDll, "InitVocalSipStack");
        adapter.m_createFunc = (CREATE_CHANNEL_FUNC)GetProcAddress( hDll, "CreateVocalSipGCChannel");
        adapter.m_cleanupFunc = (CLEANUP_PROTOSTACK_FUNC)GetProcAddress( hDll, "CleanupVocalSipStack");
#else
        void* h_dl = dlopen(VOCALSIP_DLLPATH,RTLD_NOW | RTLD_GLOBAL);
        adapter.m_initFunc = (INIT_PROTOSTACK_FUNC)dlsym( h_dl, "InitVocalSipStack");
        adapter.m_createFunc = (CREATE_CHANNEL_FUNC)dlsym( h_dl, "CreateVocalSipGCChannel");
        adapter.m_cleanupFunc = (CLEANUP_PROTOSTACK_FUNC)dlsym( h_dl, "CleanupVocalSipStack");
#endif

posted @ 2009-03-20 11:41 martin_yahoo 閱讀(1295) | 評論 (0)編輯 收藏

2009年3月18日 #

mutex與semaphore的區(qū)別

"互斥(mutext)和旗語(semaphore)之間有什么不同?"這樣的問題簡短而有力,但要回答卻相當困難.即使有經(jīng)驗的實時操作系統(tǒng)(RTOS)用戶在區(qū)別如何正確使用mutex和semaphore時也存在著困難.
但這一點很不幸而且很危險,因為無任這兩種原生RTOS中的哪一種被錯誤使用,都會導(dǎo)致嵌入式系統(tǒng)出現(xiàn)意想不到的錯誤,特別是這些系統(tǒng)為有關(guān)生命安全的產(chǎn)品時.
有關(guān)mutex和semaphore的荒誕說法是它們是相似的,甚至是可以互換的.正確的事實是盡管mutex和semaphore在它們的執(zhí)行上有相似之處,但是我們還是應(yīng)該在使用它們時加以區(qū)別對待.
最普遍(但也是不正確)的答案是:mutex和semphore非常相似,它們只有一個區(qū)別,那就是semaphores的計數(shù)可以超過1. 差不多所有的工程師都能正確的理解:mutex是一個二進制標志,可以通過它來確保執(zhí)行流在代碼關(guān)鍵區(qū)(critical section of code)互相排斥,從而對共享資源加一保護.但當他們被要求進一步回答如何使用"計算方法semaphore"的方式時,大部分工程師的回答就如同教科書書一般的刻板---semaphore用于保護多重同類資源.
通過類比辦法,我們很容易解釋為什么"多重資源"場景是有缺陷的.如果你認為一個mutex是由操作系統(tǒng)擁有的關(guān)鍵值的話,我們可以很容易地將個別的mutex比喻是城市咖啡店中一間浴室的鑰匙.如果你想使用浴室,卻找不到鑰匙,你就必須在一個隊列中等候.同樣地,mutex則協(xié)串行化多項任務(wù),以取得全域資源的共享,并且為等待隊列中的任務(wù)分配一個靜候其循序漸進的位置.
但這種簡單的資源保護協(xié)議并不使用于兩間相同浴室的情況.如果把一個semaphore概括為一個mutex,使其能保護兩個或更多相同的資源,那么在我們的比喻中,它就象是放著兩把相同鑰匙的藍子,你可以用任何一把打開任何一扇浴室的門.
因此,semaphore本身并不能解決多個相同資源的問題.咖啡店中的客人可能只知道有一把鑰匙,但并不知道哪間浴室可用.如果你試圖以此方式使用semaphore,你將會發(fā)現(xiàn)需要更多的狀態(tài)信息---它們通常是由不同的mutex所保護的共享資源.
正確使用semaphore是為了使信號從一項任務(wù)傳至另一項任務(wù).mutex意味著取得與釋放,使用受保護共享資源的每一次任務(wù)都是以這樣的順序進行.相比之下,使用semaphore的任務(wù)通常不是發(fā)送信號,就是進入等待狀態(tài),不可能同時發(fā)生.
例如,任務(wù)1可能包含程序代碼,當按下"電源"(power)按鈕時,即可提出(如發(fā)送信號或增量)一個特別的semaphore; 任務(wù)2則依據(jù)相同的semaphore而用于喚醒顯示器. 在這種情況下,其中一項任務(wù)是信號的生產(chǎn)者,另一項任務(wù)是信號的消費者.

用一個例子來做總結(jié),首先展示如何使用mutex:
/* Task 1 */
mutexWait(mutex_mens_room);
// Safely use shared resource
mutexRelease(mutex_mens_room);

/* Task 2 */
mutexWait(mutex_mens_room);
// Safely use shared resource
mutexRelease(mutex_mens_room);

相應(yīng)地,你總是采用下列方法使用semaphore:
/* Task 1 - Producer */
semPost(sem_power_btn); // Send the signal

/* Task 2 - Consumer */
semPend(sem_power_btn); // Wait for signal

重要的是,semaphores可以被interrupt service routine(ISR)中斷服務(wù)程序用來向task發(fā)送信號.發(fā)送一個semaphore是一個非阻塞的RTOS行為,并且ISR安全.因為這種技術(shù)排除了在task級別的為了是中斷不使能而引起的錯誤的可能性,從ISR中發(fā)出信號是一種使嵌入式軟件更加可靠的設(shè)計方式.

http://www.embedded.com/columns/guest/210605040?printable=true
http://www.eettaiwan.com/ART_8800557420_676964_NT_a22f6436.HTM

posted @ 2009-03-18 15:37 martin_yahoo 閱讀(22105) | 評論 (4)編輯 收藏

2009年3月17日 #

應(yīng)用系統(tǒng)中的定時器設(shè)計

     摘要: 前一段時間,讀symbian文檔資料,和Darwin,ICE等開源代碼,經(jīng)常碰到定時器和定時器事件.故對定時器的實現(xiàn)進行了一些整理,作為讀書筆記,以防以后忘記.  閱讀全文

posted @ 2009-03-17 17:34 martin_yahoo 閱讀(2523) | 評論 (2)編輯 收藏

2009年3月11日 #

線程間數(shù)據(jù)傳遞

 

在以前的multi-process程序中,process之間通過共享內(nèi)存、操作系統(tǒng)提供的消息對列,命名管道等不同方式進行數(shù)據(jù)傳遞。為了減少內(nèi)存,以及進程切換時引發(fā)的上下文切換的開銷,現(xiàn)在的系統(tǒng)一般采用multi-thread 工作方式。

process都有各自獨立的地址空間,并且是專有的,因此一個process不能通過指針訪問另一個process中的地址空間。而屬于同一process的各thread,它們共享同一process的地址空間,因此一個thread可以通過指針訪問另一個thread中的地址。這樣我們可以在應(yīng)用中自己定義消息隊列,并對消息隊列的訪問進行管理,簡化程序并提高性能。

 

multi-thread應(yīng)用中,我們可以使用消息對列來在不同thread之間進行消息傳遞,并降低各thread之間的藕合。

它們之間的關(guān)系如下:

生產(chǎn)者:向消息隊列中放數(shù)據(jù)的線程。

消費者:從消息隊列中取出數(shù)據(jù)的線程。

 
 生產(chǎn)者 ----> 消息隊列 ----->消費者

 

如果應(yīng)用規(guī)定消息隊列的最大長度。在對隊列進行控制時,應(yīng)該當消息隊列滿時,可能要讓生產(chǎn)者進行等待,直到消息隊列中有新的位置可以放入新的消息。當消息隊列為空時,應(yīng)該讓消費者進行等待,知道有新的消息被加到消息隊列中。

 

在該模型中有兩點需要注意:

1.不同生產(chǎn)者,消費者同時并發(fā)操作消息隊列時,對各操作的串行化。這個問題可以通過對隊列的操作進行加鎖來實現(xiàn)。它的實現(xiàn)可以參考另一篇隨筆《C++同步鎖管理的一種方法》。

2.在消息隊列為空或滿時,應(yīng)用程序的處理。

這可以在C++中采用Monitor.Monitor中對某種條件進行監(jiān)控。

Monitor 對象可以采取的動作:

(1)、等待操作 wait(long timeout = INFINITE), 缺省情況下無限等待下去。

(2)、發(fā)信號操作 signal(long count = 1), 缺省情況下激活一個正在消息隊列上進行等代的線程。

 

對于Monitor的實現(xiàn),可以很簡單地用下列兩種方式實現(xiàn):

1、采用ACE中的ACE_Event, ACE_Thread_Semphore實現(xiàn)。

2、采用 ICECond實現(xiàn), Linux上,Cond實際上是通過pthread_cond_t來實現(xiàn)的。

 

posted @ 2009-03-11 12:30 martin_yahoo 閱讀(3745) | 評論 (0)編輯 收藏

2009年3月9日 #

智能指針的代碼實例

前段時間,寫了一點關(guān)于智能指針的東西,有讀者反映沒有代碼比較難懂.現(xiàn)給出源碼,并稍微加以解釋.

智能指針類用到的基類的定義:
template<typename T>
class HandleBase
{
public:

    typedef T element_type;

    T* get() const
    {
        return _ptr;
    }
   
   //重載->操作符,返回所指對象的指針.

    T* operator->() const
    {
        if(!_ptr)
        {
            //
            // We don't throw directly NullHandleException here to
            // keep the code size of this method to a minimun (the
            // assembly code for throwing an exception is much bigger
            // than just a function call). This maximises the chances
            // of inlining by compiler optimization.
            //
            throwNullHandleException(__FILE__, __LINE__);
        }

        return _ptr;
    }

//  通過智能指針獲取所指對象的引用.

    T& operator*() const
    {
        if(!_ptr)
        {
            //
            // We don't throw directly NullHandleException here to
            // keep the code size of this method to a minimun (the
            // assembly code for throwing an exception is much bigger
            // than just a function call). This maximises the chances
            // of inlining by compiler optimization.
            //
            throwNullHandleException(__FILE__, __LINE__);
        }

        return *_ptr;
    }

    operator bool() const
    {
        return _ptr ? true : false;
    }

    void swap(HandleBase& other)
    {
        std::swap(_ptr, other._ptr);
    }

    T* _ptr;

private:

    void throwNullHandleException(const char *, int) const;
};

......


// 智能指針類定義

template<typename T>
class Handle : public HandleBase<T>
{
public:

    Handle(T* p = 0)               //智能指針的構(gòu)造函數(shù)
    {
        this->_ptr = p;

        if(this->_ptr)
        {
            this->_ptr->__incRef();         //在構(gòu)造函數(shù)中增加所指對象的引用計數(shù)
        }
    }

    template<typename Y>                  //拷貝構(gòu)造函數(shù)
    Handle(const Handle<Y>& r)
    {
        this->_ptr = r._ptr;

        if(this->_ptr)
        {
            this->_ptr->__incRef();   //在構(gòu)造函數(shù)中增加所指對象的引用計數(shù)
        }
    }

    Handle(const Handle& r)         //拷貝構(gòu)造函數(shù)
    {
        this->_ptr = r._ptr;

        if(this->_ptr)
        {
            this->_ptr->__incRef();    //在構(gòu)造函數(shù)中增加所指對象的引用計數(shù)
        }
    }

    ~Handle()
    {
        if(this->_ptr)
        {
            this->_ptr->__decRef();      //在析構(gòu)函數(shù)中減少所指對象的引用計數(shù)
        }
    }

// 重載=操作符, 要注意所有權(quán) (即,對原實例的處理).

    Handle& operator=(T* p)         
    {
        if(this->_ptr != p)
        {
            if(p)
            {
                p->__incRef();      //增加新指對象的引用計數(shù)
            }

            T* ptr = this->_ptr;
            this->_ptr = p;

            if(ptr)
            {
                ptr->__decRef();   //減少原來所指對象的引用計數(shù)
            }
        }
        return *this;
    }

    template<typename Y>
    Handle& operator=(const Handle<Y>& r)
    {
        if(this->_ptr != r._ptr)
        {
            if(r._ptr)
            {
                r._ptr->__incRef();   //增加新指對象的引用計數(shù)
            }

            T* ptr = this->_ptr;
            this->_ptr = r._ptr;

            if(ptr)
            {
                ptr->__decRef();      //減少原來所指對象的引用計數(shù)
            }
        }
        return *this;
    }

    Handle& operator=(const Handle& r)
    {
        if(this->_ptr != r._ptr)
        {
            if(r._ptr)
            {
                r._ptr->__incRef();            //增加新指對象的引用計數(shù)
            }

            T* ptr = this->_ptr;
            this->_ptr = r._ptr;

            if(ptr)
            {
                ptr->__decRef();            //減少原來所指對象的引用計數(shù)
            }
        }
        return *this;
    }

 跟智能指針配合使用的對象.要能夠跟指針智能配合使用,這些對象應(yīng)該是從下列類的派生類的實例.
class SimpleShared
{
public:

    SimpleShared();
    SimpleShared(const SimpleShared&);

    virtual ~SimpleShared()
    {
    }

    SimpleShared& operator=(const SimpleShared&)
    {
        return *this;
    }

    void __incRef()
    {
        assert(_ref >= 0);
        ++_ref;
    }

    void __decRef()
    {
        assert(_ref > 0);
        if(--_ref == 0)               // 如果引用計數(shù)為0,則摧毀對象本身.
        {
            if(!_noDelete)
            {
                _noDelete = true;
                delete this;
            }
        }
    }

    int __getRef() const
    {
        return _ref;
    }

    void __setNoDelete(bool b)
    {
        _noDelete = b;
    }

private:

    int _ref;
    bool _noDelete;
};

class Shared
{
public:

    Shared();
    Shared(const Shared&);

    virtual ~Shared()
    {
    }

    Shared& operator=(const Shared&)
    {
        return *this;
    }

    virtual void __incRef();
    virtual void __decRef();
    virtual int __getRef() const;
    virtual void __setNoDelete(bool);

protected:

#if defined(_WIN32)
    LONG _ref;
#elif defined(ICE_HAS_ATOMIC_FUNCTIONS)
    volatile int _ref;
#else
    int _ref;
    Mutex _mutex;
#endif
    bool _noDelete;
};

posted @ 2009-03-09 16:07 martin_yahoo 閱讀(2253) | 評論 (6)編輯 收藏

僅列出標題  下一頁
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久久久久久精| 欧美日韩一区在线观看视频| 午夜亚洲福利| 91久久精品国产91久久性色tv| 在线播放日韩专区| 国产日本亚洲高清| 国产精品每日更新| 国产精品永久免费| 国产精品免费网站在线观看| 欧美日韩视频免费播放| 国产精品国产自产拍高清av| 欧美日韩中文在线| 国产精品久久久久久久久 | 你懂的成人av| 毛片一区二区| 欧美天堂亚洲电影院在线观看| 欧美日韩国产精品一区| 久久精品视频播放| 欧美激情四色| 欧美网站在线观看| 在线成人中文字幕| 亚洲精品国精品久久99热一| 一区二区三区回区在观看免费视频 | 亚洲免费影院| 久久香蕉国产线看观看网| 久久手机精品视频| 国产精品国产a级| 国产亚洲欧美一级| 91久久精品美女高潮| 欧美在线免费播放| 欧美激情国产精品| 欧美激情1区| 性色av一区二区三区在线观看| 久久久久久久一区| 午夜视频在线观看一区二区三区 | 一区二区高清视频| 美女视频黄 久久| 欧美系列一区| 国产综合欧美| 亚洲私人影院| 老牛嫩草一区二区三区日本| 亚洲精品日韩精品| 亚洲网在线观看| 亚洲电影一级黄| 99精品国产在热久久| 亚洲国产另类久久精品| 翔田千里一区二区| 欧美久久久久久久久久| 最近中文字幕mv在线一区二区三区四区| aa亚洲婷婷| 免费亚洲一区二区| 久久综合精品国产一区二区三区| 欧美激情自拍| 久久久久久综合| 国产精品久久久久久妇女6080 | 一卡二卡3卡四卡高清精品视频| 亚洲一区二区三区在线播放| 美女尤物久久精品| 久久久久99精品国产片| 国产精品久久久久久久久久久久久 | 亚洲欧美国产日韩中文字幕| 亚洲国产视频直播| 久久久噜噜噜久久中文字免| 国产精品久久久久久妇女6080 | 亚洲国产精品福利| 久久这里有精品15一区二区三区| 国产在线国偷精品产拍免费yy| 亚洲深夜福利在线| 亚洲黄色一区| 欧美激情综合网| 亚洲黄一区二区| 欧美成人亚洲成人日韩成人| 久久精品亚洲热| 韩日精品中文字幕| 欧美成人精品一区| 久久久久国产精品一区二区| 欧美日韩综合精品| 小黄鸭精品密入口导航| 亚洲视频一区在线观看| 欧美日韩123| 亚洲欧美国产高清| 亚洲一区综合| 黄色成人在线网站| 久久精品九九| 欧美综合国产| 亚洲乱码国产乱码精品精 | 国产日韩精品一区观看| 欧美一区二区黄色| 午夜天堂精品久久久久| 国产农村妇女毛片精品久久麻豆| 午夜激情久久久| 久热re这里精品视频在线6| 亚洲激情av| 亚洲精品影院在线观看| 国产欧美日韩视频一区二区| 两个人的视频www国产精品| 久久久久9999亚洲精品| 欧美国产日本韩| 亚洲欧美综合v| 小处雏高清一区二区三区| 欧美一区二区三区成人| 好看的av在线不卡观看| 99这里有精品| 黑人巨大精品欧美黑白配亚洲| 欧美不卡在线视频| 国产美女高潮久久白浆| 久久综合999| 久久久水蜜桃| 欧美日韩中文字幕精品| 久久久久久久久蜜桃| 欧美日韩福利| 久久一区二区三区av| 欧美日韩国产成人在线观看| 美乳少妇欧美精品| 欧美日韩亚洲天堂| 性欧美精品高清| 欧美日韩成人一区二区| 久久免费观看视频| 国产精品一区二区三区久久久| 欧美成年人网站| 国产精品人人做人人爽人人添| 亚洲人体影院| 红杏aⅴ成人免费视频| 中日韩美女免费视频网址在线观看| 亚洲国产欧美日韩| 亚洲欧美日韩一区二区| 欧美亚洲成人免费| 日韩一区二区精品在线观看| 极品中文字幕一区| 欧美一区三区三区高中清蜜桃| 在线亚洲免费| 欧美专区日韩专区| 久久精品国产精品亚洲精品| 久久色在线播放| 欧美mv日韩mv国产网站| 国产区精品在线观看| 午夜精品在线| 亚洲欧美日韩天堂一区二区| 欧美自拍偷拍| 欧美成人黄色小视频| 狠狠色综合日日| 久久久欧美精品sm网站| 久久精品在线观看| 国产女主播一区二区| 久久成人人人人精品欧| 久久国产精品久久国产精品| 欧美婷婷久久| 亚洲乱码视频| 99国产精品视频免费观看| 欧美日韩精品免费观看视频| 亚洲第一在线综合在线| 国产精品综合不卡av| 欧美一区二区在线观看| 久久久久久综合| 亚洲国产欧美在线人成| 米奇777在线欧美播放| 欧美成人资源| 亚洲一区美女视频在线观看免费| 欧美日韩妖精视频| 亚洲伊人伊色伊影伊综合网| 久久精品国产清自在天天线| 国产亚洲精品自拍| 免费成人黄色av| 亚洲高清不卡在线| 亚洲综合日本| 国产亚洲精品高潮| 久久精选视频| 中文精品视频| 欧美激情精品久久久久久变态| 国产综合网站| 久久se精品一区精品二区| 免费观看不卡av| 亚洲精品美女| 欧美了一区在线观看| 性伦欧美刺激片在线观看| 久久久人成影片一区二区三区观看| 在线播放日韩| 欧美日韩专区| 欧美影院精品一区| 久久精品主播| 亚洲人成在线播放| 国产精品久久久久一区二区三区共| 亚洲一区三区在线观看| 一本久久a久久精品亚洲| 国产亚洲欧美日韩在线一区| 免费亚洲电影在线| 欧美在线视频全部完| 亚洲欧洲在线观看| 在线视频你懂得一区二区三区| 狠狠入ady亚洲精品| 欧美国产日韩二区| 久久不见久久见免费视频1| 亚洲精品在线视频| 亚洲欧美一区二区三区在线| 亚洲人成精品久久久久| 国产精品日本精品| 欧美日韩在线观看一区二区| 久久精品国产91精品亚洲| 亚洲片在线资源| 欧美高清自拍一区|