程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 【編程好習慣】青睐小粒度鎖

【編程好習慣】青睐小粒度鎖

編輯:關於C語言

在多任務環境中,不可避免的需要用到鎖以防止競爭問題,鎖可以用mutex或直接開關中斷等方式來實現。當對關鍵代碼或數據進行訪問之前需要上鎖,然後在使用完了以後則需要解鎖。作為一個好習慣,應當使上鎖的粒度及可能的小。

對於圖1的代碼,timer_init()函數在對_handler數據結構進行初始化之前,在123行先進行上鎖操作,在完成了數據結構的初始化之後,則在145行進行解鎖操作。這段代碼在功能上沒有問題,但是它沒有做到讓上鎖的粒度盡可能的小。如果仔細看這段代碼,讀者將發現在124行會檢查mark_變量是否已被設置為TIMER_MARK所定義的值,如果已設置則進行出錯處理,其邏輯依據就是一個已初始化的定時器不能被再一次初始化。繼續往下看的話,讀者能看到在144行會對mark_變量進行設值操作。

example.c
00096: typedef struct tag_timer
00097: {
00098:     dll_node_t node_;
00106:     ...
00107: } timer_instance_t, *timer_handler_t;
00108:
00109: // guard for initialized timer
00110: static const csize_t TIMER_MARK = 0x20091026;
00111:
00112: error_t timer_init (timer_handler_t _handler, msecond_t _duration,
00113:     expiration_cb_t _cb, const char *_name)
00114: {
00122:     ...
00123:     timer_lock ();
00124:     if (TIMER_MARK == _handler->mark_) {
00125:         // if it has been initialized then failing it
00126:         timer_unlock ();
00127:         return ERROR_T (ERROR_TIMER_INIT_INITIALIZED);
00128:     }
00129:
00130:     // convert to TICK_DURATION_IN_MSEC unit
00131:     _handler->ticks_ = _duration / TICK_DURATION_IN_MSEC;
00132:     if (0 == _handler->ticks_) {
00133:         _handler->ticks_ ++;
00134:     }
00135:     _handler->cb_ = _cb;
00136:     _handler->state_ = TIMER_INITIALIZED;
00137:     dll_node_init (&_handler->node_);
00138:     if (0 == _name) {
00139:         _handler->name_ [0] = 0;
00140:     }
00141:     else {
00142:         strncpy (_handler->name_, _name, sizeof (_handler->name_));
00143:     }
00144:     _handler->mark_ = TIMER_MARK;
00145:     timer_unlock ();
00146:
00147:     return 0;
00148: }圖1

那如何減小上鎖的粒度呢?其實,只要將圖1中的114~115行向上移就行了,更改後的代碼如圖2所示,短短的124~130行就能保證上鎖的時間最小,且不失競爭問題的避免。

example.c
00112: error_t timer_init (timer_handler_t _handler, msecond_t _duration,
00113:     expiration_cb_t _cb, const char *_name)
00114: {
00122:     ...
00123:     timer_lock ();
00124:     if (TIMER_MARK == _handler->mark_) {
00125:         // if it has been initialized then failing it
00126:         timer_unlock ();
00127:         return ERROR_T (ERROR_TIMER_INIT_INITIALIZED);
00128:     }
00129:     _handler->mark_ = TIMER_MARK;
00130:     timer_unlock ();
00122:     ...
00148: }圖2

為什麼要盡可能減小上鎖的粒度呢?從timer_init()單個函數的實現來看或許看不出優點,但是別忘了,一個模塊通常有多個函數,其中的多個函數都可能且很有可能)要進行上鎖操作。當這種模塊被多個任務所調用時,其上鎖粒度將影響整個系統的實時性和性能,如果盡可能減小上鎖的粒度的話就有助於提高系統的實時性和性能。

timer_init()函數中所展現的是鎖的時間維度的粒度,除此之外,還有資源維度的粒度。如果一個模塊需要A和B兩個不同的獨立資源,且這一模塊中的有些函數只需用到A資源、有的函數則只需要用到B資源,當然,也有的函數需要同時使用A和B兩個資源。在A和B都需要運用鎖進行保護的情形下,應當為A和B設計兩把不同的鎖而不是同一個,也就是說通過“專鎖專用”來減小鎖的粒度。顯然,減小資源維度的粒度的目的最終還是為了減小時間維度的粒度。

本文出自 “至簡李雲” 博客,請務必保留此出處http://yunli.blog.51cto.com/831344/273752

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved