5.19 0:10 更新(完成)
5.17 18点 更新
Starting with dmd version 2.030, the default storage class for statics and globals will be thread local storage (TLS), rather than the classic global data segment. While most D code should just compile and run successfully without change, there can be some issues.
从dmd2.030开始,静态类和全局类将默认是局部线程,而不是经典的全局数据段。虽然大多数D代码应该仍能编译和运行成功,但还可能有一些问题。
1. Performance of TLS variables. TLS 变量性能
2. Identifying TLS variables. 标识 TLS 变量
3. Switch to Immutable. 切换到不变量。
4. Marking as shared。 标识共享。
5. Cowboying with __gshared. ???
6. Compile errors. 编译错误
7. Link errors. 链接错误
Performance of TLS variables TLS 变量性能
Yes, reading or writing TLS variables will be slower than for classic global variables. It'll be about 3 instructions rather than one. But on Linux, at least, TLS will be slightly faster than accessing classic globals using PIC (position independent code) compiler code generation settings. So it's hard to see that this would be an unacceptable problem. But let's presume it is. What can we do about it?
是的,读或写 TLS 变量将比经典的全局变量慢,它将大约是3个指令(而非一个)。但在Linux上,至少 TLS 将会比访问经典 PIC(position independent code 浮动地址代码) 代码快少许,
1. Minimize use of global variables. Reducing the use of globals can improve the modularization and maintainability of the code anyway, so this is a worthy goal.
1、最少的使用全局变量。减少使用全局变量能改善代码的模块化和可维护性,所以这是一个值得追求的目标。
2. Make them immutable. Immutable data doesn't have synchronization problems, so the compiler doesn't place it in TLS.
2、标识他们不变。不变量数据没有同步性问题,因此,编译器不会把它放入TLS。
3. Cache a reference to the global. Making a local cache of it, and then accessing the cached value rather than the original, can speed things up especially if the cached value gets enregistered by the compiler.
3、全局变量的引用。制作它的局部缓存,然后访问缓存值,而不是原来的,可以加速处理特别是,假如这个缓存值从编译器得到一个 enregistered
4. Cowboy it with __gshared.
Identifying TLS variables 标识 TLS 变量
The first step is to find all the global variables, so they can be reviewed for disposition.
首先是找到所有的全局变量,这样他们就可以进行评估。
Given the complexity of source code, it isn't always easy to identify the global variables. Since it (used to be) implicit, there's no way to grep for them. It's hard to be sure you've found them all.
提供一个复杂的源代码,并不总是容易确定全局变量。因为它(曾经是)隐式的,没有办法去 grep(查找,unix术语)他们,你很难确定你能全部找到他们。
A new dmd compiler switch was added, -vtls. Compiling with it on will print a list of all the global variables that are now defaulting to thread local storage.
dmd 编译器添加了一个新的开关 -vtls 。用它编译将打印所有的全局变量清单,现在已默认是本地线程。
int x;
void main()
{
static int y;
}
dmd test -vtls
test.d(2): x is thread local
test.d(6): y is thread local
====================================================
5.17 18点 更新
Switch to Immutable 切换到不变量。
Immutable data, once initialized, never changes. This means that there are no synchronization issues with multithreading, and so no need to put immutable data into TLS. The compiler will put immutable data into classic global storage, not TLS.
不可改变的数据,一旦初始化,将永远不可改变。这意味着在多线程中就没有同步的问题,所以没有必要把不变量数据转化为 TLS 。编译器将把不变量数据转化为经典的全局存储,而不是 TLS 的 。
A good chunk of global data falls into this category. Just mark it as immutable and it's done.
一个很好的大块全局数据属于这一类。只要标示它为一成不变的,它就会工作。
int[3] table = [6, 123, 0x87];
becomes:
变为:
immutable table[3] x = [6, 123, 0x87];
Immutability is also nice because it opens the door for further compiler optimizations.
不变量非常好,因为它进一步开启了编译优化的大门。
Marking As Shared 标识共享。
Global data that is meant to be shared among multiple threads should be marked with the shared keyword:
全局数据是指在多个线程之间用 shared 关键字标明共享的数据
shared int flag;
shared int 标识:
Not only does this cause flag to be put into classic global storage, it is also typed as being shared:
这个标志不仅会转化为经典的全局存储,它也是类型化共享的:
int* p = &flags; // error, flags is shared
// 错误, flags 是共享的
shared(int)* q = &flags; // ok 正确
The shared type attribute is transitive (like const and immutable) are. This enables static checking and sharing correctness.
类型化共享特性是可传递的(类似于常量和不变量)。这导致静态检查和正确共享
Cowboying ??? With __gshared
Sometimes, none of the above solutions will be acceptable:
有时,以下的解决方案都不可接受时:
1. interfacing with C code that uses classic globals
c 接口使用经典的全局变量
2. just get it working, and go back and fix it later
让它正确工作,回头再修复
3. the app is single threaded only, so no sharing issues
应用程序仅是单线程的,没有共享问题
4. you need every erg of performance
你需要 erg 级的性能 (尔格秒 ergs, 1 ergs 1 gcm²s³ ??
)
5. you want to handle all the synchronization issues yourself
你想自己来处理所有的同步问题
As D is a systems language, of course there's a way to do this. Use the storage class __gshared:
D 作为是一个系统级语言,当然还有办法做到这一点。就是使用存储类 __gshared :
__gshared x; (这样是不是更好:__gshared Class x ; ???)
void main()
{
__gshared int y;
}
__gshared stores the variable in the classic global data segment.
__gshared 将变量存储在经典的全局数据中。
Naturally, __gshared is not allowed in safe mode.
当然, __gshared 是不允许在安全模式中使用。
Using __gshared makes such code easily searchable when doing QA code reviews or when going back later to fix any workarounds.
当使用QA代码审查或稍后再回来修复任何周边问题时,使用 __gshared 将使得这种代码容易搜索。
====================================================
5.19 0:10
Compile Errors 编译错误
The most common compiler error related to TLS will be:
有关TLS最常见的编译器错误:
int x;
int* p = &x;
test.d(2): Error: non-constant expression & x
错误:非恒定表达式 & x
While this works with classic global variables, it won't work with TLS variables. The reason is because TLS variables don't have a location in memory known to either the linker or the loader. It's a runtime computed value.
此时与经典的全局变量相比,TLS 变量它不会工作。这是因为 TLS 变量没有在内存区去 linker 或 loader 。这是一个运行时计算值。
The solution is to initialize such things in a static constructor.
解决的办法是在一个静态构造函数内去初始化这些东西。
Link Errors link错误
Sometimes you may encounter strange error messages from the linker about the global variables. These are nearly always caused by one module putting the variable in TLS, and another putting that same variable in classic global storage. This can happen when linking code with libraries that were built with earlier versions of dmd. Check that libphobos2.a was properly replaced with the latest. It can also happen when interfacing with C. C globals default to being classic global, although C does support TLS declarations. Make sure the corresponding D declarations match the C ones in terms of TLS or classic global.
有时候,你可能会从连接的全局变量遇到奇怪的错误信息。这些几乎都是在一个模块中放入 TLS 变量,另一个模块则放入一些同样的经典全局变量造成的。这种情况可能会发生在用早期的 dmd 版本来 build 连接的代码库。检查 libphobos2.a 为最新的。当使用 c 接口时它也有可能发生。C 经典的全局变量不支持 TLS 的声明。请确保 D 的 TLS 声明与 C 的经典全局变量相匹配。
int x;
extern int y;
__thread int z;
extern (C)
{
extern shared int x;
shared int y;
extern int z;
}