[心得] pthread 多绪程式设计

楼主: descent (“雄辩是银,沉默是金”)   2015-04-29 10:38:52
( http://goo.gl/WfJDto )
平时有准备, 就不怕书绝版, 对于 thread, 我不是很熟悉, 它很复杂, 也是我少有接触
的领域, 不过这次躲不过了, 我决定好好的来了解一下 thread。
不知道这本书是来的太早还是太晚, 中文版本在 199711 出版, 英文版 (
http://goo.gl/RCHmT6 ) 1996 出版, windows 95 正好流行于这年代, windows 95 带来
不少技术, thread 是其中之一, 而 thread 开始变成人人朗朗上口的名词, 好像不知道
这名词, 又要被人嘲笑, 今年已经是 2015 年, 在程式设计圈, thread 已经是无人不知
的名词了。
这是争议很大的出版社 - 松格出版的, 该出版社已经消失了。译者是萧伯刚, 台大资工
升四年级暑假翻译的, 厉害; 不是因为他读台大而厉害, 而是把这本书翻的很好, 除了因
为是台大的高材生之外, 当然也是因为他掌握了 thread, 文字很通顺, 很口语化, 例如
: p238 “一昧的相信函式库只会导致你除错除到吐血为止”, 而保留英文术语不译, 这
是我喜欢的翻译方式。我在 201410 左右才开始读这本书, 看来准备的英文版本应该派不
上用场。
最近阅读的都是简体中文的书籍, 繁体中文的电脑技术书籍在质与量上已经和中国愈差愈
远了, 这本还是 1997 年出版的, 台湾出版社加加油。
pthread 发展了这么长的一段时间, 有很多机制都已经帮程式员想好了, 我们只要知道这
些东西如何使用, 几乎就可以处理大部份恼人的 thread 问题, 这本书就是在介绍这些东
西。
另外一本好书是《Win32 多绪程式设计 ( http://goo.gl/PjIwGN )》, 我一直以为我会
由这本 thread 书籍来学习 thread programming, 毕竟侯老师比较有知名度, 书的质量
也很好, 但我显少使用 windows, 就当作藏书囉!
( http://goo.gl/Gd9sZT )
有时候会收到是否要卖书的 mail, 好书难得, 这些都是我的珍藏, 舍不得卖。我自己也
有好多好书因为绝版买不到而锤心肝, 我能理解你的感受。
晤 ... 这本竟然能卖到 2000 元, 好书难求, 绝版好书更是难寻, 不过我不想当冤大头
, 我有另外的方法求书。
( http://goo.gl/r2WDdU )
定价 500, 我应该是买 8 折吧, 英文版在台湾拍卖上便宜点 7xx nt, 不过对使用中文的
你我来说, 中文版才更具价值, 尤其是好的翻译本, 好书再贵都有人要买。
每个专业人士都会有自己的工具箱, 顶层是什么、中间层放什么、最下层又是哪些玩意儿
, 各凭自己的意志, 你的工具箱里头只有 google 吗? 也许你太高估自己了。我知道有初
学 c 语言的人 (你看他们在论坛问的问题就知道了, 完全就是没看书所提的问题, 也难
怪会有人不高兴了), 凭著 google 找资料学习, 不知道为什么他们要省下这书钱, 就算
是初学等级的书籍, 也会有足以收藏一辈子的大作。
你说书会过时, 尤其是在这快速更新的 it 产业, 我承认, 那你觉得这本 1997 的
pthread programming 有过时吗? 也许你可以看完本文后再思考一下答案, 选择一本好书
并没有想像中的容易, 买到烂书就容易不少, 我对选书颇有自信, 本本收藏的都是好书。
本书程式码的排版很糟糕, 有不少程式书籍都这样, 程式码连行号都没有, 我真是搞不懂
排个程式码有什么难的 (别说书了, 我连在 blog 的程式码都有行号), 会比做 index 还
难吗? 不过这本特别糟, 有的 if/else 没对好, 也没有行号, 好像是手工打的, 有些还
有错误, 需要对照范例程式码免得被误导。OH! 松格阿松格 ... 你是怎么做书的阿?
我已经了解 process, thread 也在我想像中, 对 os 来说, process 可以想成是 thread
。但只有这样的认识并不足以写出执行良好的 thread 程式, 只是能正常的执行, 更别说
是以 thread 增进效能, 但仅仅只是要写出正确的 thread 程式, 基本要求也得要了解不
少 thread 的观念才能做到。
chapter 1 介绍了什么是 thread, 什么样的程式才能用 thread 加速, 当然你想用
thread 来减速程式的执行也不是不行。还介绍了使用 multi-process 和 mulit-thread
的范例, 让读者们对这两种程式有所了解。
而 cpu 若只有单核心, 有些程式就算用了 thread 也是无法加速的, 若对这样的观念没
有清楚认识, 可能会误用 thread, 基本上需要等某些事情发生的程式, thread 都可以帮
上忙; 至于在多 cpu 上, thread 自然就如鱼得水了。
chapter 2 说明 thread 的使用模型, 这是经验的累积, 也许在不同的工作上, 你自己会
发现自己的使用模型。
boss/worker mode
peer mode
pipeline mode
一旦你的需求和这些模型类似, 就可能可以采取这样的方式来设计你的 thread 程式。
本章有两个范例:
一个银行的 atm 程式, 先来一个循序式的版本, 再提供 multi-thread 版本。这个 atm
程式使用的是 boss/worker mode, 也就是 boss 这个 thread 到处接工作, 产生
worker thread 让他们有事情做, 这样公司才有收入可以发薪水给他们。
另外一个是矩阵运算, 也是一个循序式的版本, 一个 multi-thread 版本。这样可以让我
们比较 multi-thread 带来的好处。
chapter3 介绍 thread 的同步机制:
pthread_join
mutex
condition variable
pthread_once
你知道几样呢? 如果你只知道 mutex, 那你知道为什么有这本书了, 350 页可不厚假的
。这是复杂的一章, 谈的就是 lock 机制。从最简单的一个 mutex 开始, 到 mutex 和
condition variable 的合体, 再到好几个 mutex 和好几个 condition variable 一起始
用。一旦有哪个 lock 和 unlock 没配合好, 这个 thread 程式就出错了, 脑袋得很清楚
才行。lock 多了, 嗯 ... 程式很安全, 但效能不好, 还不如不要用 thread, 累死自己
又怀疑怎么 thread 都没能增加效能, 增加的只有笑能吧! 书的范例提供一些技巧, 但手
上的程式码, 总无法像是书中这么理想, 得自己想办法, 证明自己的价值。
本章的例子是一个 linked list, 示范使用 mutex 来锁住读写操作。condition
variable 也用了一个简单的范例来说明, 需搭配 mutex 来使用, 整个等待/唤起过程有
点复杂, 牵扯到 mutex 的拥有与释放。
本章最后提到如何限制 thread 的数量, ATM 服务器关机时如何处理, thread pool 的建
立方式。这些都不是很容易想到的技巧, 透过书本来学习这些前人的智慧, 轻松多了。
这章就几乎把写 thread 要注意的事项都提点完毕, 算是重点章节。
chapter 4 在阐述 thread 的管理, 一开始是 thread 属性的设定, 例如设定某个
thread stack 的位置/大小。再来是 pthread_once 的用法。
Keys: Using Thread-Specific Data 的用法算是蛮好用的, 不过 thread function 都需
要用到型别转换, 应该会难倒 c 语言初学者。我当初对于 socket 的型别转换也是伤透
脑筋, 想不出来为什么要这样用。这类似 c++ std::map 可以用 key 来储存/取得某个
thread 自己的资料结构。
这是另外一个 socket api 的例子
int getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
struct addrinfo **res);
呼叫 getaddrinfo 之后, 还得记得要 freeaddrinfo(result), 而 res 本身又是个复杂
的 linked list 资料结构, 有兴趣可以参考 man page 的用法, 虽然难不倒你, 但用起
来实在太复杂。
canel thread 就是把某个 thread 结束掉, 不过 thread 并不是那么单纯可以直接结束
掉, 要是这个 thread 拥有一个 mutex, 而没有释放就把它结束掉, 那问题就大了, 你不
希望这样的程式码发生在核四上吧。
pthread 提供 cancelability type, state 来支援取消 thread, function 不难用, 难
的是怎么使用这些机制来让 thread 程式运作正常, 这不是容易的事。
这里的观念是 cancelability type, state 和取消点, 当 cancelability type 是
PTHREAD_CANCEL_DEFERRED, 发动取消, 在程式码的某些会发生取消的效果, 如果你没预
期到这些, thread 可能在你不知道的地方被结束了, 有可能 bug 就发生在这里, 这是很
难复制的 bug。
这节有个范例, 支援 atm server 的取消存款的动作, 仔细阅读一番, 你会发现要考虑周
到, 不是容易事。而这些程式码都要付出代价, 若是不符合效益, 那还不如不要支援取消
功能, 赔了夫人又折兵罢了。
请参考这个范例:
http://maxim.int.ru/bookshelf/PthreadsProgram/htm/r_36.html#854257 (
http://goo.gl/BCAUJf )
接着是 thread 的排程, 读过有概念就好, 毕竟提供优先权这些属性的成效, 只有试过才
知道。比较重要的概念是 priority inversion, 若是一个优先权较低的 thread 握有一
个 mutex, 那优先权高的 thread 也无技可施, 得等, pthread 提供了 pritority
ceiling, priority inheritance 来处理这问题。这是把 mutex 和 thread 本身的优先
权做个结合。
pritority ceiling: 如果拥有该 mutex 的 thread 优先权低于该 mutex, 会将该
thread 优先权提高和 mutex 一样。
priority inheritance: 将持有这个 mutex 的 thread 优先权提高到和等待中的
thread 一样。
page 209 有个发电厂的例子, 你一定马上想到我们的核四会不会有同样的问题吧!
chapter 5 谈到和 unix 之间的互动, unix 有 fork, signal 当这些东西通通和
thread 扯在一起的时候会怎么样呢? 会很麻烦, 麻烦到程式出错时很难找到原因, 你得
用猜的, 看是不是出在这些问题上。
我补充了一篇自己的心得:
http://descent-incoming.blogspot.tw/2015/01/thread-signal.html (
http://goo.gl/9dKfjj )
另外一个是在 thread 中使用 fork 的问题, 比较明显的是 child process 继承了
parent process 的 mutex, 而这个 mutex 是在 lock 的状态, 对 child process 来说
, 我还没 lock mutex, 怎么就已经 lock 住一个 mutex 了, 所以有个 pthread_atfork
来处理这问题。
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void
(*child)(void));
这个函式看来不好惹, 事实上也的确很复杂, 书中的提到的例子得要花点脑筋来理解。
chater 6 讲的东西比较杂, 有 kernel thread, user space thread, 把这两种混合的
thread 实作。支援 thread 的 debugger (digit unix 上的除错器)。比较各种情形下
multithread, multiprocess, single process 的执行效率, mulitthread 可不是完胜,
在某些情形下, 不使用 thread 反而是有比较好的效率。
后面三个附录很轻松, 随意浏览即可。
ref:
千头万绪 : 学习多执行绪程式设计的好书 ( http://goo.gl/pS0xJd )
Programming with POSIX Threads
POSIX多程程序中文版 ( http://goo.gl/O5xNCF )
// 本文使用 Blog2BBS 自动将Blog文章转成缩址的BBS纯文字 http://goo.gl/TZ4E17 //
blog 版本:
http://descent-incoming.blogspot.tw/2015/02/books-pthread.html

Links booklink

Contact Us: admin [ a t ] ucptt.com