再谈多线程信号量同步(协调)方法的本质

我在上一篇文章中说到信号量的关键是:并行化。


但我真的来写一个并行化的数据库连接池时,突然发现还多地方只能串行化。例如下面是池中一个数据连接对象的定义

  TDBConnection = record
    Connection : TADOConnection;
    InUse: Boolean;
    Count: Integer;
    LastActivityDateTime: TDateTime;
  end;

当某个线程要求取得池中一个连接对象时,我要对使用标识赋值为True,对计数器加1,记下使用时间,这几个操作必须是串行的。


这样的话,使用信号量来并行化还有意义吗?


想了半天仍然不能解决问题,反复的看我在前一篇文章中感谢的网友(万一 http://www.cnblogs.com/del/category/174761.html)其写下的多线程示例代码发现有误导性地方:

1、Canvas.Lock()和Canvas.Unlock()本身已经在使用临界区。所以其示例代码已经变为了多线程协调(请注意,我不会在正文中使用“同步”这个词,而是使用协调)嵌套代码。结果当然是信号量的示例其实是伪并行。

2、每个线程在循环中都规律的调用Sleep(线程调用Sleep函数将立即退出CPU)。 也就是这些示例代码表现为均匀的的线程调度。把万一示例代码中的Sleep中的时间变大一些,就会发现,每个线程调用Canvas画出的数值增长是均匀的(每个线程轮流加1)。这与实际中的应用出入非常大。


在一片混乱持续了很长时间后我想有两个重要的问题把我卡住:

1、Windows对线程的调度机制是什么?因为我根本不知道Windows是如何调度线程的。

2、需要反过来想:什么样的协调代码可以并行化?


问题1、Windows对线程的调度机制是什么?因为我根本不知道Windows是如何调度线程的。

经过大约二到三个小时后,我明白了要完全搞明白这个问题在考虑各个版本的Windows及一些特殊情况下,问题的结果是WOW中一句经典台词:你们这是自寻死路。

挑一些重要的概念来说明:

1、线程存在优先级,优先级的高的线程如果进入等待运行状态。那么Windows会放弃当前低优先级线程的执行来执行高优先级的就绪线程。当线程被抢先时,它被放回相应优先级的就绪队列的队首。

2、每个线程被分配CPU时都有一个时间配额(时间片),但这个值是多少无法确定。时间配额是一个线程从进入运行状态到系统检查是否有其他优先级相同的线程需要开始运行之间的时间总和。(这个问题没有完,原因看另一篇文章:“错误的CPU时间片概念” http://blog.csdn.net/blue_morning/article/details/7843581)

3、一个线程用完了自己的时间配额后,如果没有其它相同优先级线程等待就绪,Windows 将重新给该线程分配一个新的时间配额,并继续运行。

以上我认为重要的说明有需要注意的东西:

一、你控制的多线程中、线程的优先级是首先要考虑的。如果多个线程存在不同的优先级,那么问题将明显的复杂化。

二、一个线程在CPU上执行时,时间配额是一定存在的,虽然我们不能确定是多少,但我们应该保证协调代码的执行尽可能的短。


问题2、需要反过来想:什么样的协调代码可以并行化?

明白这个问题首先要知道:即使是同一进程下的多个线程,各个线程的栈也是独立的。反过想很容易得到的结论是:需要协调的并不是代码,也不是可以放入不同线程栈上的东西。而是可以被协调代码访问到的公共资源,这些资源不是代码,而是数据。所以所谓的并行本质仍是串行。因为我想不出也写不出任何可并行但同时需要访问公共数据的代码。我唯一能做到的:就是保证在线程获得CPU时,能完成协调代码段。


以上分析得到结论就是:

信号量本质上并不是一种线程协调方法,和并行化也没有关系。而是定义需协调资源可以有多少个线程进行访问。其本质是一种资源控制手段,目的是避免Windows系统的资源耗尽。


使用信号量来编写数据库连接池资源,并不是可以让线程并行的使用池中的对象而是把池中的对象出池和回池使用信号量来计数。另外因为等待函数可以控制TimeOut,所以相同临界区的傻等来说可以写出让用户体验更好的代码。


例如Wow的登录前的排队系统就可以理解为信号量使用的一个最好例子。


前一篇文章中如果有误导了大家的地方,望谅。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值