多线程中局部静态变量初始化陷阱:http://www.rxyj.org/html/2010/0424/279529.php
多处理器环境和线程同步的高级话题:http://baiy.cn/doc/cpp/advanced_topic_about_multicore_and_threading.htm
如何解决静态变量的线程安全问题:http://www.programfan.com/club/showtxt.asp?id=294156
Imperfect C++:Chapter 11 Statics:11.3Function-Local static objects
多个lwp进程中的函数局部静态变量初始化会碰到啥问题?
发信人: colyli (coly), 信区: KernelTech
标 题: [合集] 线程的问题
发信站: 水木社区 (Wed Jan 10 02:09:30 2007), 站内
☆─────────────────────────────────────☆
feiy (积极、乐观、率性、自信) 于 (Thu Apr 29 12:30:05 2004) 提到:
关于线程(thread)之间的数据共享
1) 按照OS传统的观点,进程是程序的一次执行,一个进程和其他进程的区别在于
其上下文(context)完全不同。而线程则是一个进程的不同执行流(executing
flow),一个线程和其他线程的区别在于执行流不同,属于同一个进程的不同
线程可能共享一部分上下文(包括存储空间)。因此,进程和线程是属于两个
不同层面上的概念。
2) 但是,Linux简单化的处理原则,把线程(thread)直接当作一类特殊的进程来
处理,它把所谓的轻量级进程(Lightweight Process, LWP)和线程的概念联系
起来,用LWP来实现了线程的功能。
3) LWP进程本身也是一个进程,因此具有独立的进程描述符(包括独立的内核堆栈),
它也和其他普通的进程一样被内核调度,和其他进程一样也被内核分配独立的
堆栈空间(因此包括独立的局部变量空间)。从本质上讲,除了几点特殊之处
外,内核对进程的许多操作并不区分一个进程是否是一个LWP。
4) LWP是一类特殊的进程,它的一个特点是在创建的时候,将直接从创建它的
进程“复制”内存描述符和页表映射信息(即传递给系统调用sys_fork的标
志包括CLONE_VM)。
换句话说,如果LWP中的某个变量与创建它的进程中的某个变量具备相同的线性
地址(或者叫做虚拟地址,其实也就是逻辑地址),那么它们也会映射到相同
的物理地址。
而对于其他普通的进程,由于页面映射表是重新分配的,和创建它的进程的页面
映射表不同,因此,即使这两个进程中某些变量具备相同的逻辑地址,但是依然映
射到不同的物理地址。
比如,全局变量在编译后,在两个进程中具备相同的逻辑地址,但是如果创建的
进程是LWP,那么在两个进程中看到的这个全局变量会映射到相同的物理地址,
因此在一个进程(线程)中修改这个全局变量,其他的线程都会"看到"这种变化。
这也就是所谓的线程之间的数据共享。
而对于普通的进程,每个进程具备不同的页面映射关系,所以尽管这个全局变量
在两个进程中具备相同的逻辑地址,但是依然映射到不同的物理地址,因此一个
进程修改它的一个逻辑地址对应的物理地址的内容,不会影响另外一个进程的相
同逻辑地址所对应的物理地址,因为两个物理地址是不相同的。
归纳之,普通进程之间的内存描述符和页表映射信息是不同的,因此,对于所声明的
全局变量,即使具备相同的逻辑地址,也会映射到不同的物理地址。而对于LPW和创建
它的进程之间,内存描述符和页表映射信息是直接复制的,因此,对于所声明的全局
变量,尽管位于不同的进程中,但是由于具备相同的逻辑地址,因此会映射到相同的
物理地址。这样便实现了线程之间的部分数据的共享。
感兴趣的人可以分别用thread_create()和fork()创建不同的线程/进程,-S 编译观察
全局变量和局部变量的逻辑地址的分配,然后链接执行看看结果的差异。
btw: 上述陈述仅限于用户态,在内核态因为采用相同的页面映射机制,所以不存在上述
区别。