[编程好习惯] 青睐小粒度锁
来源:李云 责任编辑:栏目编辑 发表时间:2013-07-01 09:00 点击:次
在多任务环境中,不可避免的需要用到锁以防止竞争问题,锁可以用mutex或直接开关中断等方式来实现。当对关键代码或数据进行访问之前需要上锁,然后在使用完了以后则需要解锁。作为一个好习惯,应当使上锁的粒度及可能的小。
对于图1的代码,timer_init()函数在对_handler数据结构进行初始化之前,在123行先进行上锁操作,在完成了数据结构的初始化之后,则在145行进行解锁操作。这段代码在功能上没有问题,但是它没有做到让上锁的粒度尽可能的小。如果仔细看这段代码,读者将发现在124行会检查mark_变量是否已被设置为TIMER_MARK所定义的值,如果已设置则进行出错处理,其逻辑依据就是一个已初始化的定时器不能被再一次初始化。继续往下看的话,读者能看到在144行会对mark_变量进行设值操作。
对于图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: }
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: &n
00112: error_t timer_init (timer_handler_t _handler, msecond_t _duration,
00113: expiration_cb_t _cb, const char *_name)
00114: {
00122: ...
00123: &n
相关新闻>>
- 发表评论
-
- 最新评论 更多>>