Linux系统开发专栏

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  51 随笔 :: 0 文章 :: 48 评论 :: 28万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

     多核基本意味着多线程,那么在多线程处理中有一个比较棘手的问题:当存在一些常驻的线程访问的共享数据时,退出时必须先结束这些常驻线程才能对共享资料进行释放操作。否则,先释放这些共享资源,后面的常驻线程访问这些已经释放了的共享数据时,导致程序异常。比如下面的情况:

     QQ截图20111106215039
     分析上述例子可以发现,问题出在当释放掉链表后,访问链表的线程依然存在,怎样才能在释放链表前让其他对链表有操作的线程安全的退出呢?这就要求我们设计一定的算法而不能简单地使用线程退出函数来强制某个线程的退出,而是在算法中实现让线程自己主动地退出。
     要将对链表这样供多个线程操作的线程在链表前安全地退出,首先要做到的就是让这些线程知道要进行释放操作了,这里要分几种情况讨论:

      1.单个子线程退出算法

     这种情况是最简单地情况,因为只有一个线程,可以通过设置一个退出标志的方式来实现。具体地说就是再进行释放操作要进行的时候先设置一个退出一个标志,在子进程中要定期检测这个标志, 如果子进程检测到这个退出标志为真时就退出线程,在子进程具体退出过程中,也要让释放操作的线程知道操作链表的子进程已经退出,这个可以通过让子线程在退出的最后一步发送一个事件通知,释放线程就可以安全地进行释放操作了。具体的方案如下图:

     QQ截图20111106220112

      2.多个线程退出算法

     和1相比,麻烦在于此时有多于一个的子线程,如果每个子线程都在退出前发送一个事件通知给释放操作的线程,就可能出现第一个子线程退出就发送了事件通知,而此时还有其余的子线程还在进行对链表的访问操作,但释放操作的线程已经收到了事件通知,进行了释放。这时显然是会出现问题的。解决这个问题的关键就在于释放链表操作的线程在知道所有的子线程都退出的时候再进行释放的操作。
     这时问题的关键就在于如何让释放操作的线程知道所有的子线程都已经安全退出了呢?这里我提起一个新的概念----读写锁。在读操作进行过程中,要进行写操作,必须要等到所有的读操作结束后再进行。写操作的线程是通过一个计数变量来判断是否还有其他读操作线程的。当有一个读操作进行读时,会将计数器+1,一旦读操作完成,会将计数器-1,这样在计数器为0时就表示没有读操作进行了。我们可以把这个方案拿来用在这里。我们把释放操作的线程和写操作相对应,把对链表操作的线程和读操作对应。它们之间维护着一个计数器,当有操作链表的线程创建工作时就把计数器+1,一旦完成时就把计数器-1,该线程然后再检测一次计数器的值,如果计数器为0,就向释放链表操作的线程发送退出事件,否则就不发送,这样当最后一个线程对计数器作-1操作时会为0,会发送退出事件,这样释放操作的线程就可以安全的释放链表了。该算法的实现流程如下所示:

      QQ截图20111106222256

     至于最后的源码实现,这里不给了,目前有两种方法:利用锁来完成和原子操作两种方式来完成。这里的加/解锁和原子操作只要是为了维持计数器的值,防止多线程同时对其修改的目的。

posted on   ☆&寒 烟☆  阅读(1184)  评论(2编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示