{技术}{多线程}多线程服务器的常用编程模型

20 views
Skip to first unread message

Shuo Chen

unread,
Feb 12, 2010, 8:51:16 AM2/12/10
to TopLanguage
本文主要讲我个人在多线程开发方面的一些粗浅经验。总结了一两种常用的线程模型,
归纳了进程间通讯与线程同步的最佳实践,以期用简单规范的方式开发多线程程序。

万字长文,慎入。
PDF 版下载: http://files.cppblog.com/Solstice/multithreaded_server.pdf

目录

1 进程与线程
2 典型的单线程服务器编程模型
3 典型的多线程服务器的线程模型
One loop per thread
线程池
归纳
4 进程间通信与线程间通信
5 进程间通信
6 线程间同步
互斥器(mutex)
跑题:非递归的mutex
条件变量
读写锁与其他
封装MutexLock、MutexLockGuard 和Condition
线程安全的Singleton 实现
归纳
7 总结
后文预览:Sleep 反模式

Tinyfool

unread,
Feb 12, 2010, 8:54:52 AM2/12/10
to pon...@googlegroups.com
C++实在是不在行,好好的看了一遍,还是不太懂

2010/2/12 Shuo Chen <gian...@gmail.com>



--
Tinyfool的开发日记 http://www.tinydust.net/dev/
代码中国网 http://www.codechina.org
myTwitter: http://twitter.com/tinyfool

机械唯物主义 : linjunhalida

unread,
Feb 12, 2010, 9:09:03 AM2/12/10
to pon...@googlegroups.com
看起看起。0bug事件没过多久就出来叫阵好文,这打脸太狠了吧?

2010/2/12 Tinyfool <tiny...@gmail.com>

机械唯物主义 : linjunhalida

unread,
Feb 12, 2010, 9:46:49 AM2/12/10
to pon...@googlegroups.com
感觉这篇文章还是深层次的交流性质的文章,
如果在c++和boost上面加点注释方便非c++程序员阅读就好了。
不过,好像非C++程序员也很少有机会接触到造轮子的状况,一般直接用封装好的库。。

2010/2/12 机械唯物主义 : linjunhalida <linjun...@gmail.com>

机械唯物主义 : linjunhalida

unread,
Feb 12, 2010, 9:51:43 AM2/12/10
to pon...@googlegroups.com
其实我更关注如何根据需求,来考虑到底是用:
单线程阻塞,
单线程非阻塞(是否有点类似while loop forever+中断?)
多线程(消息传递,共享内存,线程存在的意义,是否是作为一个资源的管理者?)
大量线程(线程池)
多进程,
大量进程(进程池)
还有再上面的集群。。。

以及不同状况下的设计方法和调试方法。

2010/2/12 机械唯物主义 : linjunhalida <linjun...@gmail.com>

jinhu wang

unread,
Feb 12, 2010, 9:57:58 AM2/12/10
to pon...@googlegroups.com
  • 关于进程和线程介绍,我印象比较深的一个总结大约是7年前一个朋友说的
线程:资源竞争的最小单位.
进程:资源分配的最小单位
  • 进程间通信我实践的不多,主要用过udp socket。
比较有意思的技巧方面只记的周伟明先生讲过他很早的时候利用可共享的socket的bind阻塞特性,来实现进程间保护切换的功能,感觉很有意思,同时也意识到了进程间通信水好深。
  • 可重入锁那一节里引入一个不可冲入的消息队列的实现,跟前面那个线程池的实现模型相悖,这个例子放到前边专门介绍一下线程间的消息队列的实现就好了。
  • 单线程模型服务器事实上是用select或poll等事件分离机制接管了操作系统的tick调度。内部实现了一个小型操作系统,很适合早期多线程多进程操作系统模型不完善的场合。线程池适合高并发多cpu的场合,现在的http服务器应该还是有很多用这个模型的吧!还有一种类似观察者的线程,就是主接收线程收到的包需要做简单的拆分再做dispatch,例如协议栈一般会用这样的模型。
  • Singleton的多线程安全模型是我一直感觉小题大作的东西,直接在程序入口处或者程序启动前把Singleton初始化好就成了,避免引入过多的概念到项目里面。

jinhu wang

unread,
Feb 12, 2010, 10:02:50 AM2/12/10
to pon...@googlegroups.com
还有最后的sleep,除了测试外,在很多软件里是需要有定时器这么个组件的,定时器要么依赖系统的已有实现,要么自己另启一个线程sleep一段时间发一个消息激活自己,要么自己sleep保证时间间隔。
单线程模型中就是用你说的select或poll的超时机制干这活,但是精确度要自己算或者在实现的框架里面算也是个挺麻烦的事。

机械唯物主义 : linjunhalida

unread,
Feb 12, 2010, 10:03:26 AM2/12/10
to pon...@googlegroups.com
不是还有一个叫协程的,更轻量级的东东吗?

http://zh.wikipedia.org/wiki/%E5%8D%8F%E7%A8%8B



2010/2/12 jinhu wang <wangji...@gmail.com>

Shuo Chen

unread,
Feb 12, 2010, 10:07:22 AM2/12/10
to TopLanguage
这篇文章原来有一节叫"多线程的应用场景",限于时间和篇幅没有放进去,这节还没有写完,年后再说吧。

On Feb 12, 10:51 pm, 机械唯物主义 : linjunhalida <linjunhal...@gmail.com>
wrote:


> 其实我更关注如何根据需求,来考虑到底是用:
> 单线程阻塞,
> 单线程非阻塞(是否有点类似while loop forever+中断?)
> 多线程(消息传递,共享内存,线程存在的意义,是否是作为一个资源的管理者?)
> 大量线程(线程池)
> 多进程,
> 大量进程(进程池)
> 还有再上面的集群。。。
>
> 以及不同状况下的设计方法和调试方法。
>

> 2010/2/12 机械唯物主义 : linjunhalida <linjunhal...@gmail.com>


>
> > 感觉这篇文章还是深层次的交流性质的文章,
> > 如果在c++和boost上面加点注释方便非c++程序员阅读就好了。
> > 不过,好像非C++程序员也很少有机会接触到造轮子的状况,一般直接用封装好的库。。
>

> > 2010/2/12 机械唯物主义 : linjunhalida <linjunhal...@gmail.com>
>
> > 看起看起。0bug事件没过多久就出来叫阵好文,这打脸太狠了吧?
>
> >> 2010/2/12 Tinyfool <tinyf...@gmail.com>
>
> >> C++实在是不在行,好好的看了一遍,还是不太懂
>
> >>> 2010/2/12 Shuo Chen <giantc...@gmail.com>

jinhu wang

unread,
Feb 12, 2010, 10:08:59 AM2/12/10
to pon...@googlegroups.com
不同的操作系统,有些实现方式是不一样的。大家比较熟悉的应该就是线程和进程。
vxworks早期中只有task,task的调度方式是进程的方式,但是却又是线程的资源共享的特性。新版本的vxworks又有了rtp,非内核态的进程。
ose操作系统的调度单位叫process。听起来是进程吧。但是同一cpu上的有process间可以互访数据,记忆里好像还有父子process、模块等概念。另外它的process又是针对多cpu集群的。你在一个cpu上可以看到所有cpu上的process,你跟其他cpu上的process可以通过signal通信。而实现原理是你在a cpu上看到的b cpu的process实际上是个phantom process。很有意思。

SpitFire

unread,
Feb 12, 2010, 10:09:07 AM2/12/10
to pon...@googlegroups.com
正好想问一下,跨机器的message queue有哪些轻量高效的实现?苦苦寻找中

2010/2/12 Shuo Chen <gian...@gmail.com>



--
SpitFire

jigsaw

unread,
Feb 12, 2010, 10:09:06 AM2/12/10
to pon...@googlegroups.com
这些已经成了 trivial 的范畴了。。。

2010/2/12 机械唯物主义 : linjunhalida <linjun...@gmail.com>:

Shuo Chen

unread,
Feb 12, 2010, 10:15:49 AM2/12/10
to TopLanguage
我没有听说过 MQ (没理解错的话是 IBM 那种,MS 也有自己的实现,需要单独安装一个服务啥的)有"轻量级和高效"的,它本来就是重量级的协
议。

On Feb 12, 11:09 pm, SpitFire <spitfi...@gmail.com> wrote:
> 正好想问一下,跨机器的message queue有哪些轻量高效的实现?苦苦寻找中
>

> 2010/2/12 Shuo Chen <giantc...@gmail.com>

jinhu wang

unread,
Feb 12, 2010, 10:18:59 AM2/12/10
to pon...@googlegroups.com
类似tipc那样的东西?

oliver yang

unread,
Feb 12, 2010, 10:49:48 AM2/12/10
to pon...@googlegroups.com
我一直觉得SUN的图书Multithreaded Programming Guide是多线程编程的经典之作。

刚才大概看了看你的文档, 你关于Semaphore的文字大概可以用这本书的章节作为答案:


http://docs.sun.com/app/docs/doc/816-5137/sync-11157?a=view

The two basic sorts of semaphores are binary semaphores and counting
semaphores. Binary semaphores never take on values other than zero or
one, and counting semaphores take on arbitrary nonnegative values. A
binary semaphore is logically just like a mutex.

However, although not always enforced, mutexes should be unlocked only
by the thread that holds the lock. Because no notion exists of “the
thread that holds the semaphore,” any thread can perform a V or
sem_post (3RT) operation.

Counting semaphores are nearly as powerful as conditional variables
when used in conjunction with mutexes. In many cases, the code might
be simpler when implemented with counting semaphores rather than with
condition variables, as shown in Example 4–14, Example 4–15, and
Example 4–16.

另外这本书还介绍了另外一种同步机制就是Barrier,其实就是基于Memory Barrier实现的。

多线程编程在用户层是可选的,在内核里却是必须的。Pthread的线程同步机制在内核里都有对应实现,所以说,精通多线程编程的人,写内核程序应该会顺手很多了。


在 2010年2月12日 下午9:51,Shuo Chen <gian...@gmail.com> 写道:

--
Cheers,

Oliver Yang

Twitter: http://twitter.com/yangoliver
Blog: http://blog.csdn.net/yayong
--------------------------------------------------------------------
An OpenSolaris Developer

SpitFire

unread,
Feb 12, 2010, 9:31:30 PM2/12/10
to pon...@googlegroups.com
类似于memcacheQ的东西,不过不需要持久化,可能根据这个更改一个适合我的需求的东西

2010/2/12 jinhu wang <wangji...@gmail.com>



--
SpitFire

sagasw

unread,
Feb 17, 2010, 1:56:05 AM2/17/10
to pon...@googlegroups.com
非常不错的文章,简略读了读,也感觉颇有收获。

我个人对于多进程多线程的经验不多,都是windows下编程的经验,来自几本比较经典的多线程编程书籍,其中侯捷翻译过一本。
前一阵还在TL问过一个类似问题,后来发现实际上也算是一个IO相关的设计问题(windows注册表频繁读写效率低下),写完了几个修改版本,也是不了了之,没有实际测试,也没有性能比较,大概两周时间算是白费,自己倒是多少练习了一下多线程多进程同步的代码。在这里发个牢骚,小程序员就是这么惨,领导一个屁,蹦出二里地。

感觉比较值得分享的几点粗浅经验是:

1,能不用多线程就不要用。单线程单进程最简单,也不容易出错,尽管效率很重要,要是程序出错了那么效率就是非常不重要的一点了。

2,能不加锁就不要加。我曾经参与过一个项目,代码里加了很多锁,后来仔细读来读,发现这写代码只会用到singleton模式下,跟领导提了去锁的建议,没被采纳,嘿嘿。

3,多线程是要多写才能得到锻炼,大型网站、银行金融领域(如楼主)、网游这几个领域应该是非常容易把多线程、多进程练熟的。如果感兴趣的朋友,还是应该转到类似行业。像是我搞工业自动化编程方面,几乎用不到多线程多进程这样的知识,想熟练精通何其难也。

------------------------------------
C++, Lua, living in Dalian
http://sunxiunan.com/
http://twitter.com/sagasw
------------------------------------


2010/2/12 Shuo Chen <gian...@gmail.com>

徐建忠

unread,
Feb 19, 2010, 9:18:45 PM2/19/10
to pon...@googlegroups.com
如果不需要持久化的话,我觉得zeromq正合适,开销小,性能优异。

SpitFire

unread,
Feb 19, 2010, 9:35:57 PM2/19/10
to pon...@googlegroups.com
谢谢推荐,正在研究,跟我的需求比较合

2010/2/20 徐建忠 <xui...@gmail.com>



--
SpitFire

anders.zhao

unread,
Feb 19, 2010, 9:43:14 PM2/19/10
to pon...@googlegroups.com
文章看了2/3,颇有收获,谢谢分享~~

kellerman Deng

unread,
Feb 21, 2010, 9:51:52 AM2/21/10
to pon...@googlegroups.com
文章写得很好

对文中的一个观点十分赞同,在多线程/分布式环境下,去反复优化单机性能是没有什么意义的

扩展性/稳定性才是最重要的

--
Best Wishes
  Yours Honestly
Kellerman

陨落雕

unread,
Feb 22, 2010, 1:16:49 AM2/22/10
to TopLanguage
扩展性和稳定性与反复优化单机性能没什么关系吧?觉得在高性能计算上优化单机性能潜力反而巨大。平均一个程序第一次优化会有大概50%的性能提升,也就
是说第一次优化就可以节约1/3的服务器购买花销。
Reply all
Reply to author
Forward
0 new messages