程序设计语言

多线程中局部静态变量初始化

2010年10月24日 阅读(530)

多线程中局部静态变量初始化陷阱: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: 上述陈述仅限于用户态,在内核态因为采用相同的页面映射机制,所以不存在上述
区别。

You Might Also Like