在多任务环境中,不可避免的需要用到锁以防止竞争问题,锁可以用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设计两把不同的锁而不是同一个,也就是说通过“专锁专用”来减小锁的粒度。显然,减小资源维度的粒度的目的最终还是为了减小时间维度的粒度。

【编程好习惯】青睐小粒度锁相关推荐

  1. gil php,网络编程之多线程——GIL全局解释器锁

    网络编程之多线程--GIL全局解释器锁 一.引子 定义: In CPython, the global interpreter lock, or GIL, is a mutex that preven ...

  2. python并发编程之semaphore(信号量)_python 之 并发编程(守护进程、互斥锁、IPC通信机制)...

    9.5 守护进程 主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就立即终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic process ...

  3. Linux多线程编程---线程间同步(互斥锁、条件变量、信号量和读写锁)

    本篇博文转自http://zhangxiaoya.github.io/2015/05/15/multi-thread-of-c-program-language-on-linux/ Linux下提供了 ...

  4. 关于小概率锁碰撞的细粒度锁方案

    文章目录 前言 锁的细粒度级别 基于小概率锁碰撞的lock pool实现方案 引用 前言 在分布式系统中,我们常常使用锁来保证操作的一致性控制.但是锁的存在则意味着必然存在着锁竞争的情况.而且这种竞争 ...

  5. 第六篇:并发-粒度锁

    目录 并发事务 – 冲突和性能问题 锁的粒度 实践中的实际粒度锁 隔离概念...树锁定和意图锁定模式 乐观锁 时间戳 并发事务 – 冲突和性能问题 多个并发运行的事务可能会导致冲突 - 我们仍然尽量允 ...

  6. 基于 abp vNext 和 .NET Core 开发博客项目 - 再说Swagger,分组、描述、小绿锁

    基于 abp vNext 和 .NET Core 开发博客项目 - 再说Swagger,分组.描述.小绿锁 https://github.com/Meowv/Blog 在开始本篇正文之前,解决一个 @ ...

  7. Nginx下配置小绿锁https

    我用的是阿里云服务器,centos7.2的操作系统,服务器类型:nginx/1.12.1 这是github上的官方配置https://github.com/Neilpang/acme.sh/wiki/ ...

  8. 小福利,用Excel VBA编程制作一个变色小游戏

    小福利,用Excel VBA编程制作一个变色小游戏 设计思想:在正方形的四条边上都是设置循环函数,不断改变颜色和单元格里面的数值. Option ExplicitSub 按钮1_Click() Dim ...

  9. https小灰锁(带黄色三角)如何变成安全的小绿锁

    随着百度和谷歌对https的重视和支持,现在很多型站点都慢慢在使用了https了.虽然我们使用了https通道还需要解析http协议百度才能识别和收录,但两种协议并存.让我们的站点显示绿色的安全小锁还 ...

最新文章

  1. 使用rest_framework写api接口的一些注意事项(axios发送ajax请求)
  2. MATLAB从入门到精通:Simulink仿真必看——连续模块之PID控制器(PID Controller)
  3. 人工智能的发展之路,居然要从春秋时期讲起?
  4. 图解排序算法之谈「选择排序」
  5. SAP SM37后台作业结果显示为alv list怎么样可以显示alv grid形式呢?
  6. LeetCode 105. 已知前序中序 求二叉树
  7. sriov查看pf-vf对应关系
  8. 29岁女程序员感慨:硕士学历,脱单比找工作买房还难,有同感么?
  9. php7会不会出问题,升级到PHP7后会话不工作
  10. C语言课程设计——学生成绩信息管理系统
  11. 弹窗php整人,bat整人代码,超级弹窗代码
  12. win10如何在当前目录打开cmd窗口
  13. strapi token expired解决方案
  14. android高德地图语音,高德地图导航组件没有导航语音声音
  15. 使用一个SQL查询出每门课程的成绩都大于80分的学生姓名
  16. 关于调用百度AI接口进行图片识别的实现(C#)
  17. Centos7 修改SSH端口,以及修改密码
  18. win7 64系统,检测有没有装SP1补丁!
  19. 如何下载并安装turbo pascal 7.0?
  20. VUE3.0从安装到应用 (2)

热门文章

  1. java流类图结构_java I/O 流总结
  2. go io.reader 多次读取_Go 语言进阶:freecache 源码学习(1)
  3. openssl、x509、crt、cer、key、csr、ssl、tls
  4. python函数定义中参数列表里的参数是_详解Python函数中参数带星号是什么意思
  5. mysql的实验环境_第04 章 MYSQL实验环境创建
  6. python 模拟浏览器selenium 微信_Spider-Python爬虫之使用Selenium模拟浏览器行为
  7. siamese网络_CVPR 2019手写签名认证的逆鉴别网络
  8. oracle 监听程序当前无法识别连接描述符中请求的服务_Go 中的优雅升级
  9. C语言解决关于兔子的古典问题的代码
  10. android实现底部弹出菜单,Android实现底部缓慢弹出菜单