1 概念

最近因为要做一点培训工作,激发了我攀爬制作演示文档这颗技能树的情绪, 因此在理论上生吞活剥了一些“别说你懂ppt”之类的东东,在实践上分别用 DrRacket的slideshow模块,\LaTex的beamer包,微软的PowerPoint做了一点点 实验。

用这些工具做“幻灯片”的时候,我对生吞活剥的那些理论产生了一点点怀疑, 那些理论无不强调利用视觉冲击表达、贩卖自己的观点,不过我的角色似乎不 是观点贩子,我们做技术培训或者技术分享的时候,并不是传递观念,而是传 递知识。

我对自己之前的误解于是有了一点理解,当大家谈论ppt、幻灯片、演示文档的 时候,往往是以presentation的背景去谈的,presentation一般来说,当然是 贩卖观点的,而presentation要借助presentation document,这个document用 ppt来做,那么如果其他什么活动需要用ppt来做,似乎就自然服从 presentation的法则了。

2 教学活动和presentation

同样适用ppt制作文档的两类活动:教学和presentation,显然是非常大的,根 本区别就在于前者传递知识,后者传递观念。当然,这两者都需要调动视觉因 素,但因为目标的不同,又有很大的区别。教学活动适用视觉因素,更多的用 于为抽象内容提供直观印象,比方画出数据结构的示意图,画出算法在数据结 构上作用的示意图,这种视觉效果对于理解问题的帮助是其他方式无可比拟 (似乎如此)的;而presentation使用视觉因素主要在于强调,吸引受众的注 意力,通过视觉上的效果塑造某种观念,比方通过视觉上的先后,灌输逻辑上 的先后次序,等等。当然,presentation对视觉因素的使用,教学活动一般的 说,也不是用不上。

教学使用的幻灯片通常即便没有老师的讲解,也能传递相当含量的信息(知 识),而presentation使用的“演示文档”,很难想象会有这样的效果。因此, 对于教学活动来说,幻灯片应该被看做“教学材料”,某种意义上是“书”。 而presentation使用的幻灯片则是“戏法”。

技术报告、技术培训和技术分享,更近于教学活动而不是presentation,一个 精心设计的技术主题的幻灯片,应该可能在不需要讲解的情况下传递主要的知 识内容。

因此,技术主题的幻灯片和“演示文档”的制作有很大的不同。比方说,技术 主题幻灯片对于动画的使用,应该主要在内容上,而不是在形式上,比如以动 画演示cpu的工作方式,而不是以动画引入、加强一句判断。比方技术主题幻 灯片对于条列(itemize)环境的使用似乎应该少一些,幻灯片应该使用各种 元素来说清楚一个问题,而不是列举问题。

当然,在技术报告中可能仅仅使用幻灯片作为一个提纲,内容完全在报告者的 肚子里,这应该不属于讨论范围。

3 工具和方法

我一共使用了三种工具:DrRacket的slideshow模块,\LaTex的beamer包, PowerPoint。最终用beamer完成的幻灯片的制作。

DrRacket是一种Scheme的实现,它提供了一个做slideshow的库,同时也是一 种语言。完全编程的制作幻灯片,这个东东在概念上很有趣,画演示动画似乎 也有方便之处。但是……它在内容元素上太弱,比方说,没有引用环境,没有 代码条列环境,而且自己通过努力也不见得能做到。对于内容型slideshow来 说,这个是致命的缺点。

beamer用的人较多,各种问题基本都能得到解决,用pgf/TikZ能画很不错的 演示图/动画。问题是,画起来有些麻烦,编译太慢。但是TikZ能够做到的也 是比较惊艳的,比方说做手绘效果的元素,用decorate还是比较容易的,而 这个非常有趣—可能也有用的一种效果。

PowerPoint应该是比较好用的,但在画一些特定的东西上,还是不如TikZ方 便,比方说画树,ppt有一个节点一个节点的去拖,而TikZ就可以自动布局, 画数组的示意图之类的,ppt都要自己把矩形元素“粘”到一起,并不是特别 方便,画这类东西,矢量绘图语言往往比图形化的绘图工具方便一些。

至于制作要点,似乎和网上的文章都差不多,无非是页面保持干净,内容不 要过多-—但也不是说不能比较多。另外,尽量少用甲乙丙丁一二三四这样 的结构,一个slide接着一个slide,就是一个问题接着一个问题,在slide上 直接、简明的说明问题,然后再以必要的元素阐释问题。

Date: 2012-03-20 Tue

Author: MaTao

Org version 7.7 with Emacs version 24

posted @ 2012-12-26 06:39 qingant 阅读(2170) | 评论 (0)编辑 收藏


1 CLI

对*nix用户来说,在Windows下生存的头等大事就是命令行设施的简陋和匮乏。 不管是终端模拟器还是shell,都比较差,cmd.exe不能改字体,shell从语法 上和Unix下各种差得远,工具也比较匮乏。PowerShell算是有一些较为先进 的设计和特性,但是对基本的问题解决的不好。下面这几种解决方案,大部 分人应该能从中选择出一个差强人意的方案。

1.1 Eshell

Eshell作为一个term和Shell都很好,但是你不见得是Emacs用户(也不建议 你成为emacs用户),另外,Eshell处理一些交互程序可能会有问题,比方 说直接跑python就不行,得用 c:/Users/matao/org $ python -i 才行。但是对IPython就不行了。

1.2 ConEmu

http://code.google.com/p/conemu-maximus5/

ConEmu是一个终端模拟器,类似Konsole,gnome-terminal之类的东东,支持 多标签,字体、颜色设置,勉强能追上Linux下面那些terminal。可以指定 shell,可以用cmd.exe,powershell,也可以用IPython(建议用IPython)。

1.3 Console2

http://sourceforge.net/projects/console/

类似ConEmu,但是感觉比ConEmu差一点。

另外,Console2用cmd.exe有Prompt错位的问题。

可以通过Console2的View -> Console Window打开一个cmd.exe窗口,更改这 个窗体的字体为新宋体就可以解决了。

1.4 IPython

IPython是Windows下比较理想的Shell,特别是对我这样的Python专家来说。 它本身是一个Python Shell,因此可以使用一个还不错的通用编程语言来做 日常工作,比*nix下那些什么csh,ksh,bash之类的bullshit强多了。而且 IPython还支持readline。

IPython有一些内置命令,和一般shell下的一致,其他的,可以用形如 In [6]: !tar 这样的去做。

当然也可以自己用Python去扩展它,以更加适合作为一种通用的Shell。

1.5 GnuWin32

http://gnuwin32.sourceforge.net/

Windows下的CLI Utility比较匮乏,gnuwin32提供了一些常用的*nix工具, 比如zip,tar,grep之类的,结合上面的命令行工具(term,shell),和 GnuWin32里面的utilities,应该能够满足比较多的需求了。

1.6 结论

如果你是一个Emacs老手,使用Eshell(结合GnuWin32),否则,使用一种 terminal emulator + IPython/cmd/powershell + GnuWin32.

2 开发

2.1 UNIX Compatable Application

使用Windows的SUA(Subsystem for UNIX-based Application) 提供的POSIX 兼容的API开发,这样开发的程序,甚至可以在*nix下用MinGW交叉编译工具 链在*nix下编译出Windows Excutable。

2.2 开发环境

C++开发者应该毫不犹豫的使用Visual Studio + Visual AssistX + VsVIM(即便目标平台并非Windows),非常好的重构功能,极大提升生产力 的编辑环境。

其他的我一般是用Emacs。

3 杂项

3.1 字体

用MacType获得Mac风格的字体渲染。

3.2 Emacs相关

  • 使用putty的plink作为tramp默认程序。

    http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html

    把plink.exe放在%PATH%下面,这样配置Emacs:

    (require 'tramp) (setq tramp-default-method "plink")  
  • M-w 不工作的问题

    QQ使用了 Alt-w 作为热键,在QQ设置里面去勾选掉这一项就行了。

  • 如何判断host os类型

    变量 system-type ,其值应该是 ="windows-nt"= .

  • el-get的替代品

    Emacs 24添加的新功能package management.用法和el-get差不多。(并 建议在所有平台下使用package)

  • 无法打开achieve文件(zip,tar,jar…)

    没有相应的解压程序,安装GnuWin32,并将gnuwin32/bin加入%PATH%即可。

3.3 Python相关

有一些包通过pip或者easy_install安装不上。这里有一个非官方的安装包 集合:

http://www.lfd.uci.edu/~gohlke/pythonlibs/

3.4 pacman/port替代品

360软件管家/QQ软件管家

Date: 2012-03-20 Tue

Author: MaTao

Org version 7.7 with Emacs version 24

Validate XHTML 1.0
posted @ 2012-10-20 20:27 qingant 阅读(2289) | 评论 (2)编辑 收藏

一般来说,Python从文件系统上的.py或者相应的字节码文件.pyc或.pyo获得一 个python module对象。有时候会需要定制这个过程,比方说,嵌入Python作为 应用容器的时候,希望有一种特别的应用打包格式,类似jar或者war,或者处 于某些原因,需要改变Python Module的物理存储,比如,处于查找性能上的考 虑,如果python module能从一个key-value数据库得到就好了,或者处于商务 上的原因,如果能对源代码(或者pyc,而pyc很容易被反编译到py)进行加密 处理就更好了。

3.2 如何定制Python Module的查找

http://www.python.org/dev/peps/pep-0302/

参考上面的链接。要点在于可以用一个实现了Import Protocol的class去 hook模块加载的过程,这个hook要被安装到sys.pathhooks.

这是一个从网络上(github)import模块的例子:

https://github.com/mitsuhiko/badideas/blob/master/githubimporter.py

Author: MaTao <qingant@gmail.com>

Date: 2012-03-20 Tue

HTML generated by org-mode 6.33x in emacs 23

 

posted @ 2012-09-02 04:27 qingant 阅读(1795) | 评论 (0)编辑 收藏


最近在人人网上看见这篇文章:

http://mindhacks.cn/2012/08/27/modern-cpp-practices/

我觉得这篇文章名字起得有点大,实际上和C++11的关系也不太大,可以说 hard core的部分基本上就是在如何在C++里面进行错误处理。这方面应该说他 写的是很好,很完整的。

实际上我们的团队基本上也是(试图)按照这样去实践的。不过我们因为不能 过分的激进,所以像ScopedGuard这种东西,都是写个”临时类“,专门去利用 RAII来做类似finally的工作(实际上比finally好用),当然也可以用宏去进 一步简化,总之,本质上没有区别。只是我们目标环境受限,不能用某些新特 性。

一般来说,像刘未鹏这样的博客名人,博文下面基本是吹捧与互相吹捧,但是 这次二楼出来一个所谓的“神吐槽”,这也是这篇文章在 人人被转发的原因:

天天和这些妖孽特性作斗争,还有时间作设计?不可能。

我特别想就这个评论说一点,是因为这个评论在我看来代表了中文技术社区的 坏风气,就是那种所谓的酷评、吐槽文化,实际上胸无一物,乱发评论。

C++可能确实有一些妖孽特性,但刘未鹏这篇文章强调的那些特性,基本上不 在妖孽特性中间,相反,那些基本上都是大部分主流工业语言经过验证采用或 者正在采用的modern特性。


这里面讲到的主要的,比方异常、lambda,std::function,这些,有哪一个是 有一点点妖孽可言的?这里面异常是酒精考验的好特性(虽然有些用C++的地方 禁止异常,但那个问题比较复杂,基本可以说和该特性本身无关),剩下这俩 都是其他语言早就证明过实用好用的特性。非要追究到底,顶多能说C++的特性 不够多,因此有些妖孽,比方说异常没有语言级别的stacktrace支持,这算一 点点妖孽,但是用glibc或者libunwind轮一个是很容易的事情,做项目的时候 做这么一点点准备性的工作,就算是在和妖孽特性做斗争?

再进一步说,刘未鹏这篇文章里面,尤其是错误处理这方面的内容,属于所谓 的“本质性困难”,也就是说,你在任何语言中都会遇到的问题, **错误处理 是本质性困难** ,恰恰是C++的妖孽特性(RAII)使得其在错误处理上竟然比哪 些“现代语言(java, python, C#)”更加方便,RAII对于异常安全是至关 重要的,这就是为什么那些所谓的现代语言纷纷引入了类似的机制,比如java 的try-with,python的with,然而这些特性都是侵入式的,就是你必须为资源管 理者指定一个特别的接口,比方说python里面,with的东西必须是 contextable的,这就比C++的很不好用。可以说,不理解RAII的重要性很大程 度上意味着写过的严肃代码比较少,没有接受过在复杂流程中进行异常处理的 挑战,没有RAII,复杂流程中的异常安全是非常、非常困难的。

为什么这种无聊的吐槽这么流行?这是技术迷信的一个表现,很多人迷信微软, 那么就有相应的人迷信鄙视微软,看起来相反,其实是一样的。一个基本的常 识是,只要有钱,技术很容易牛逼起来。微软亚洲研究院有好十几个IEEE fellow,比很多中国所谓的顶尖工科大学整个学校的还多,这叫技术不牛?包 括C#的设计,就是小小的微软拼音输入法,在整句输入这方面还是没有能够超 越的。完全可以承认微软技术很牛。linux界搞了这么多年的输入法,现在的水 平可以说勉强可用,比sogou,google什么差得远,输入法并不是什么需要大兵 团作战的项目,类似数据库,通讯中间件这样的。

实际上没有必要这样,对于不了解的事情,就踏踏实实了解,不要神化它也不 要鄙视它。现在知识高度扩散,只要花功夫,完全不能了解的东西很少,完全 做不出来的也不是太多,然而真正要做一个东西出来,也不是那么容易的。这 就需要一个恰当的平衡。建立在平心静气的为了做事情的立场上,去理解、利 用别人的工作,顺便说说这个工作做的不错,或者哪个地方有点糟,这才是实 事求是的态度。为了所谓的“设计”,为了所谓的“信仰”,去做些无聊的事 情,比方说吐槽,比方说做一些根本无用只是符合了某些抽象原则的事情,根 本是误入歧途。同技术上具体的工作一样,技术上的争论也是为了更好的出活, 更长远的出活。

Author: MaTao <qingant@gmail.com>

Date: 2012-03-20 Tue

HTML generated by org-mode 6.33x in emacs 23

posted @ 2012-08-28 01:30 qingant 阅读(370) | 评论 (1)编辑 收藏


链接在这里:

https://bitbucket.org/qingant/clojure-struct

一个类似Python标准库里面的struct的小玩意儿,用来做二进制pack/unpack, 目前大体完成了pack的部分。用起来基本是这样:

user=> (load-file "struct.clj")
#'struct/bpack
;; pack 0xff000000 大字节序 到四字节int 然后是gbk编码的字符串"好"  补
足32个字节
user=> (def ar (struct/bpack '(i > s g 32) 0xff000000 "好"))
#'user/ar
;; 结果:
user=> (seq ar)
(0 0 0 -128 -70 -61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0)
;;同上,不过是本地字节序
user=> (def ar (struct/bpack '(i  s g 32) 0xff000000 "好"))
#'user/ar
user=> (seq ar)
(-128 0 0 0 -70 -61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0)
;; 不对字符串进行补齐:
user=> (def ar (struct/bpack '(i  s g ) 0xff000000 "好"))
#'user/ar
user=> (seq ar)
(-128 0 0 0 -70 -61)
user=> 

做这个东东的主要目地是学习clojure.为啥学习clojure:
  1. 需要会一门jvm语言
  2. 会一点lisp,容易上手
  3. clojure有一些优秀特性,atom,agent之类,有严肃的并发支持

Author: MaTao <qingant@gmail.com>

Date: 2012-03-20 Tue

HTML generated by org-mode 6.33x in emacs 23

posted @ 2012-08-07 18:52 qingant 阅读(2450) | 评论 (0)编辑 收藏


在事件驱动的网络编程中进行超时处理是真正的挑战,常常要面对意想不到的 复杂性,现在有很多新发展出来的网络编程架构、运行时、语言提供某种用户 态线程的抽象,本质上,事件驱动的网络编程架构就是一种用户态协作式多线 程,只是大部分的网络架构仍然没有提供良好的“控制流”的抽象,应用不得 不面对上下文、回调这种本该属于“运行时”层面的问题。但本文还是把关注 点集中在IO调度,尤其是超时处理这个方面。

20.1 定时器

IO调度的本质上把多个阻塞集中为一个阻塞,在这一个阻塞上获取事件,发 生“中断”,挂起或者恢复(调度)原先那些本应该阻塞的控制流。在一个 控制流上并发地生产多个超时事件的东东就叫做定时器。

大体上,定时器是一个线程,接受注册超时事件,在任何一个超时事件的条件 满足时发出事件。基本的思路是用一个并发数据结构维护注册的事件,睡一段 时间醒来去看一下这个数据结构,收集满足条件的事件,根据应用上的要求, 做特定的事情(也就是发出事件)。

这里面就有两个选择,第一:选择何种数据结构,第二,怎么睡,睡多久。

关于第一个问题,使用最小堆或者优先队列应该是比较直观的想法。如果假 设比较后来进入的超时请求,应该概率上比先进入的超时请求更加迟到达, 这大部分应该是成立的,优先队列应该效率不错,但这需要评测,这两种数 据结构在一般的假设下都是合理的选择。

第二个问题,关于睡多久,自然是堆或者是队列首元素距离当前的时间,显 然,每次只要睡这么久就绝对不会错过。但是有一个问题就是当有事件注册 进来的时候,它到达的时间可能比当前堆或者队列的首元素的时间还要早, 也就是说注册之后它就是首元素了,那么这时候就要唤醒定时器,通知他更 新自己的睡眠时间。所以我们就用了一个poll做定时器,在poll上监控了一 个socket pair,用来唤醒定时器。

20.2 如何超时

应用上的超时比较好说,当然是应用要怎么超时就怎么超时。比方说超时30s 接收回复,那当然就是发出30s的超时请求。

麻烦的问题是如何进行连接超时,对连接超时的意思是说,如果连接长期空 闲,我们要把他关闭掉,或者另一种情况,我们是作为客户端,那就要向服 务端进行心跳,否则人家就把我们超时了。这里只谈服务端的情况,要判断 一个连接是不是超时,那就要维护它上面最后的读写操作发生的时间,也就 是说要有时间戳,另外,要间隔一定的时间去检查它是不是超时。

这里面主要的技巧,第一是时间戳缓存,我们还是用定时器去产生时间戳,对 定时器会有一个心跳间隔,也就是照前面的设计,不过他总是睡眠这个心跳间 隔和首元素之间较小的一个时间,每次醒来去更新一下时间戳。而在对连接 进行操作时候更新时间戳,就用定时器缓存的这个。另外,就是分代进行超 时,也就是说,不是针对每个连接,都发出一个超时请求,而是对相近的比 方一百个连接(或者最近1s产生的连接),用同一个超时请求去做超时。

posted @ 2012-08-03 07:05 qingant 阅读(586) | 评论 (0)编辑 收藏


名字写的这么绕,其实就是常用的struct initializer的写法{0},老是这么 用,习焉不察矣,今天别人问起来。想起来差了老半天C/C++标准。终于把这 个问题搞清楚了。这里以C99标准为准–—C++标准的相关部分是从C标准里面 抄来的。

很显然,标准里面对不完全的initializer list的行为是有规定的,相关表述 如下(下面引文全部引自C99标准草稿):

[6.7.8.21] If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.

也就是说,类似这样:

struct {int a;int b;} aa = {0}; 

的写法是完全没问题的,并且会把a,b都zeroing(a是从initializer literal 来的,b是上述因为规定的)。

有一个基本常识是,C里面的非复合类型(我自己造的词,那么个意思,大家别 细究了)都可以用0初始化,所以{0}初始化上面例子中类似的结构是没问题的, 有的人的疑问在于如果struct的第一个元素是struct怎么办。标准规定了这种 情况下的行为:

[6.7.8.20] If the aggregate contains elements or members that are aggregates or unions, or if the first member of a union is an aggregate or union, these rules apply recursively to the subaggregates or contained unions. If the initializer of a subaggregate or contained union begins with a left brace, the initializers enclosed by that brace and its matching right brace initialize the elements or members of the subaggregate or the first member of the contained union. Otherwise, only enough initializers from the list are taken to account for the elements or members of the subaggregate or the first member of the contained union; any remaining initializers are left to initialize the next element or member of the aggregate of which the current subaggregate or contained union is a part.

这段话很长很绕,简单的说,如果aggregate(这里简单理解为struct,准确的 表述去看标准)的某个元素是aggregate,就按照普通的aggregate初始化规则找 到该aggregate的初始化列表开始的地方,如果是大括号扩着的,就用那个括 号里面的list初始化这个aggregate,否则就从这里开始找到"足够"的条目给 自己来initialize,剩下的给别人用。

以这个例子来说:

struct {struct {int a;int b;} aa;int c;} _a = {1 ,2}; 

struct的第一个元素是struct,initializer它相应的位置没有{…}这样的东 东,而是个"1",那它就从这里拿"足够"的initializer来初始化自己,就是把 "1,2",拿来初始化a,b了。所以结果就是a == {{1,2},0};

这样,对上面这个结构用{0}初始化就很容易理解了。

Date: 2012-05-28 Mon

Author: Ma Tao

Org version 7.8.05 with Emacs version 23

posted @ 2012-05-28 18:07 qingant 阅读(24068) | 评论 (3)编辑 收藏



  在水木C++版,有人提出如何针对"基类是xx类的类型"进行特化。这里面的关键
  是理解这样几件事情:
  
  1. 模板的特化
  2. 如何在编译期判断xx是xx的基类

  
  我们使用了这样一个type traits:


 1 
 2   template <typename B, typename D>
 3   struct is_base_of // check if B is a base of D
 4   {
 5      typedef char yes[1];
 6      typedef char no[2];
 7   
 8      static yes& test(B*);
 9      static no& test();
10   
11      static D* get(void);
12   
13      static const bool value = sizeof(test(get())) == sizeof(yes);
14   };
15 
  
  关键是理解struct is_base_of的最后一行,涉及对sizeof的理解:
  

 

The sizeof operator yields the number of bytes in the object 
representation of its operand. The operand is either an expression,
which is an unevaluated operand (Clause 5), or a parenthesized
type-id.
--- Working Draft, Standard for Programming Language C++ (5.3.3)

 


  重点就是test(get())是unevaluated,编译期可以推断出该表达式的类型,如果
  D是B的子类,则`static yes& test(B*);`是更好的匹配,否则就是另一个,而
  它们返回值类型的大小不一样,藉此可以判断D是否B的子类。

  
  下面是模板类的代码:


 1 
 2   struct    Base
 3   {
 4   };
 5   
 6   template <typename T, bool nouse=is_base_of<Base, T>::value>
 7   class ATemplate
 8   {
 9   public:
10      ATemplate(  )
11      {
12         printf( "no\n" );
13      }
14      ~ATemplate(  )
15      {
16   
17      }
18   };
19   
20   
21   template <typename T>
22   class ATemplate<T,true>
23   {
24   public:
25      ATemplate(  )
26      {
27         printf( "yes\n" );
28      }
29      ~ATemplate(  )
30      {
31   
32      }
33   };
34   
35   struct D:public Base
36   {
37   
38   };
39   struct C
40   {
41   
42   };
43   
44   
45   int main(  )
46   {
47      ATemplate<C>  t;
48      ATemplate<D> t1;
49      return 0;
50   }
51 
  
  结果如下:



  $ ./t
  no
  yes

posted @ 2012-03-21 19:08 qingant 阅读(1438) | 评论 (0)编辑 收藏

参考这个下面的二:

http://blog.csdn.net/xf51357/article/details/3322026

其实也没怎么用上。千辛万苦下了个IDA Pro在上十几m的文件上就工作不能, 所以还就是nm,人肉过滤,大致先找出可疑的地方,然后一点点辛辛苦苦在 gdb里面disassamber,nexti,一路下去。

我这的TextMate版本是Version 1.5.10 (1631),还是先处理上面那个链接提 到的东东,把偏移0x5deb77的两个字节89 c8改成b0 01就行了。但是这样它还 是会跳出对话框,说是序列号过期还是什么的,反正是洋文,我也没看明白。 费了九牛二虎之力大体确定在

00048e18        calll   0x002a0539      ; symbol stub for: __ZSt4findIPKiiET_S2_S2_RKT0_
00048e1d        cmpl    %eax,%esi
00048e1f        je      0x00049030
00048e25        movl    0x0024168f(%ebx),%eax
00048e2b        movl    %eax,0x04(%esp)
00048e2f        movl    0x00242f77(%ebx),%eax
00048e35        movl    %eax,(%esp)
00048e38        calll   0x002a0d0e      ; symbol stub for: _objc_msgSend
00048e3d        movl    %eax,%edi
00048e3f        leal    0x00215743(%ebx),%eax
00048e45        movl    %eax,0x08(%esp)
00048e49        movl    0x0024170f(%ebx),%eax
00048e4f        movl    %eax,0x04(%esp)
00048e53        movl    0x00242f77(%ebx),%eax
00048e59        movl    %eax,(%esp)

单步了一下,可以确定,0x48e1f这里还不会弹出对话框,并且这里也不会跳 转倒je那个参数0x00049030,在下面的某个地方,弹出对话框,声称序列号有 问题了,那么可以合理的预期,判断这个序列号是不是对的分支就在这里。试 了试:

(gdb) set $eip=0x00049030
(gdb) c

果然就可以用了。那么就考虑让它总是执行这个je跳转就行了.

(gdb) x/x 0x00048e1d
0x48e1d <-[AppDelegate applicationDidBecomeActive:]+671>:   0x840fc639

这个 39 c6(注意字节序),就是cmpl %eax,%esi了,我把它改成cmpl %eax,%eax,那么它自然就会永远执行je跳转了。这个指令的代码就是36 c0.那 么算一算,这个指令的偏移就是在0x5dee1d附近,过去一改,就行了。

Author: qingant <qingant@gmail.com>

Date: 2011-06-12 Sun

HTML generated by org-mode 6.33x in emacs 23

posted @ 2011-08-06 18:28 qingant 阅读(3494) | 评论 (1)编辑 收藏


在Python界,我们常常使用多进程来实现并行加速。在各进程内部,再采用多 线程方案进行io调度,但这通常有一些问题,我们这里以传统的CPython实现为 准,该实现直接采用来操作系统原生线程实现多线程,这有一些问题,首先, 操作系统线程并不是免费的,它有自己的栈、内核数据结构,并且(通常)是基 本调度单元,这会带来一些并不算不重要的overhead,我们在这种场景下使用 多线程的目的本质上就是进行io调度,那么大部分的抢占对我们是没有意义的; 第二,Python实现中,每个线程执行一定条数的字节码后主动让出时间片,这 种调度时机并不是我们想要的。对于特定的应用,这可以用IO多路复用来解决, IO多路复用就是一个IO调度器,但是,这种方式不能提供一种透明的抽象,进 行IO的控制流必须显式得处理回调、事件等等,另外,我们能够同时进行的控 制流(任务)受到了不必要的限制——它本质上应该受限于我们处理IO的能力。

4.1 对控制流的抽象

我们用一个"闭包中的callable对象"来表达控制流中的某一状态,我们可以 得到这个对象,就得到了当前控制流,通过对该对象的调用恢复执行控制流。 大体上是这样:

def task(arg):
    def task_child(a):
        return some_func(arg, a)
    return task_child

对于一般的控制流的抽象,我们应该了解continuation,参考:

http://en.wikipedia.org/wiki/Continuation

4.2 设计

4.2.1 task

我们把满足下属条件的Python对象叫做task:

  1. 可以以某种确定的方式被调用,有0到多个入参
  2. 对该task的调用,应该返回
    1. Complete,结果
    2. Failed
    3. 一个list,该list由形如(head,tail1,tail2…)的元素组成,我们 把这种元素叫做task元祖

我们把满足下述条件的tuple叫做task元祖: 形如:(head, tail1, tail2…)

  1. head为一个task,且接受该tuple长度减1个参数
  2. tail1、tail2应该是:
    1. 一个Python对象
    2. 一个task元祖
  • IO task

    一个拥有触发条件的task叫做IO task.IO task只在满足触发条件的情况下 才会被调度。

4.3  实现

调度器维护一个task元组的队列,根据特定的调度策略选择task执行,执行的 结果将被投入该队列。IO task在满足触发条件的时候被调度,一种典型的IO task:

def recvsegment(s, length):
    rcv = s.recv(10000000)
    if len(rcv) == length:
        return rcv
    return lambda:rcv + recvsegment(s, length-len(rcv))

我们在每次调度的时候,会检查与一个IO task联系的标识符(文件描述符)是 否准备好,如果准备好,就执行该IO task.对于task元组中参数被求值完毕 (所有的tail都为一个值)的情况,我们会以这些参数为入参,执行head。在 这种设计下,任何IO操作应该和主控制流分离,以(head, io1,io2…)的方 式进行。

事实上,task的执行载体可以是原生线程,这样,就实现了M:N的并发模型, 对于特殊的情况(IO完成却没有机会被调度倒的task),还可以动态增减线程 进行处理。

在特定的假设下,这套多任务方案有一定的意义。这个假设就是:1.IO占据了 控制流的大部分时间。2.任何一种非IO操作都可以很快完成。因此,在特殊 的时机交出控制权,而不是抢占调度,是可以接受的。事实上,现实世界有 很多系统满足这样的要求。

Author: qingant <qingant@gmail.com>

Date: 2011-06-12 Sun

HTML generated by org-mode 6.33x in emacs 23

posted @ 2011-08-02 04:32 qingant 阅读(2516) | 评论 (2)编辑 收藏
仅列出标题
共2页: 1 2 

导航

<2011年7月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

统计

常用链接

留言簿(3)

随笔档案

相册

最新随笔

搜索

最新随笔

最新评论

阅读排行榜

评论排行榜