Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1039511
  • 博文数量: 243
  • 博客积分: 3053
  • 博客等级: 中校
  • 技术积分: 2975
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-02 21:11
文章分类

全部博文(243)

文章存档

2013年(2)

2012年(20)

2011年(5)

2010年(114)

2009年(102)

我的朋友

分类:

2009-10-25 15:05:14

上回我讲到 CS_OWNDC 这个 class style 的历史背景,以及为什么一开始大家都觉得这主意不错,但再转几念一想就觉得是个坏主意的原因。

CS_CLASSDC 这个 class style 不但一样,而且更糟。它不但继承了 CS_OWNDC 的带来的所有问题,而且还将其发扬光大。回想一下,CS_OWNDC 这个 class style 让窗口管理器为该窗口创建一个 DC 并在对 BeginPaintGetDC 的调用作出反应时使用该 DC。CS_CLASSDC 则更进一步,为属于该 class 的所有窗口创建同一个 DC。于是,上次我展示的那个由一个自认为对同一个窗口拥有两个的 DCs 的函数所引发的问题现在终于可以跨窗口地发作了。你觉得一个窗口有一个 DC,而另一个窗口有另一个 DC,可事实是它们是同一个东西。

线程甲 线程乙
HDC hdc = BeginPaint(hwnd, &ps);  
  HDC hdc = BeginPaint(hwnd, &ps);
SetTextColor(hdc, red);  
  SetTextColor(hdc, blue);
DrawText(hdc, ...);  
  DrawText(hdc, ...);

线程甲里的代码认为文本应该是红的,因为它是先把文本颜色设为红色再把文本画出来的。而它又怎么知道,就在这时,线程乙跑了过来把颜色改成了蓝的?

这就是某种竞态条件 bug,受控条件下几乎查不出来。你只会从客户那儿收到 bug 报告说大概每隔一个月就会出一回颜色问题,抑或你自己也会隔三差五地发现,可你调试器设上断点后就是没问题。就算你加上诊断代码也只会看见:

SetTextColor(hdc, red);
ASSERT(GetTextColor(hdc) == red); // 触发断言!
DrawText(hdc, ...);

很好,断言被触发了。才设置的颜色没了。现在准备干什么?可能你只会说“漏洞百出的 Windows”,然后把代码换成

// 漏洞百出的 Windows. 介于某些原因,
// 大约每隔一个月 SetTextColor 就失灵一回
// 于是我们不得不调用两回.
do {
SetTextColor(hdc, red);
} while (GetTextColor(hdc) != red);
DrawText(hdc, ...);

而即便如此也还没解决问题,因为线程乙可能在 GetTextColor 之后把颜色改蓝了,然后 DrawText 再被调用。于是乎,这回要每隔半年才会出颜色问题了。

继而你大骂微软,发誓说我从此就去开发 Mac 软件了。

OK ,希望你同意我 CS_CLASSDC 是个可怕的坏主意的想法。可如果它天生就有这缺陷,为什么打一开始就有它呢?

原来,16 位 Windows 是合作型多任务的。在 16 位世界里,你不必担心另一个线程偷偷潜进来把你的 DC 搞得一团糟,原因之前我也说过,即“你在运行就是别人不在运行”的道理。这整个多线程灾难场景发生不了,于是 CS_CLASSDC 只是小小地比 CS_OWNDC 怪异了点。而一进程多线程的抢先式多线程的引入才是真正带领我们走进“没法儿把这东西搞正常了”新时代的领路人。这样一个 class style 存在着,于是人们可以把在 16 位代码移植到 Win32 上(只要它们还是单线程应用程序),但现代软件还是不要用的好。

阅读(2504) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~