root/trunk/docsrc/migrate-to-shared.dd

Revision 1242, 6.0 kB (checked in by walter, 3 years ago)

latest

Line 
1 Ddoc
2
3 $(D_S $(TITLE),
4
5     $(P Starting with $(LINK2 changelog.html#new2_030, dmd version 2.030),
6     the default storage class
7     for statics and globals will be
8     $(LINK2 glossary.html#tls, thread local storage (TLS)), rather
9     than the classic global data segment.
10     While most D code should just compile and run successfully without
11     change, there can be some issues.
12     )
13
14 $(OL
15     $(LI $(LINK2 #performance, Performance of TLS variables).)
16     $(LI $(LINK2 #vtls, Identifying TLS variables).)
17     $(LI $(LINK2 #immutable, Switch to Immutable).)
18     $(LI $(LINK2 #shared, Marking as shared).)
19     $(LI $(LINK2 #__gshared, Cowboying with __gshared).)
20     $(LI $(LINK2 #compile-errors, Compile errors).)
21     $(LI $(LINK2 #link-errors, Link errors).)
22 )
23
24 $(H3 $(LNAME2 performance, Performance of TLS variables))
25
26     $(P Yes, reading or writing TLS variables will be slower
27     than for classic global variables. It'll be about 3
28     instructions rather than one.
29     But on Linux, at least, TLS will be slightly faster
30     than accessing classic globals using PIC (position
31     independent code) compiler code generation settings.
32     So it's hard to see that this would be an unacceptable
33     problem. But let's presume it is. What can we do about it?
34     )
35
36     $(OL
37     $(LI Minimize use of global variables. Reducing the use
38     of globals can improve the modularization and maintainability
39     of the code anyway, so this is a worthy goal.)
40     $(LI Make them immutable. Immutable data doesn't have
41     synchronization problems, so the compiler doesn't place it
42     in TLS.)
43     $(LI Cache a reference to the global. Making a local cache
44     of it, and then accessing the cached value rather than the
45     original, can speed things up especially if the cached value
46     gets enregistered by the compiler.)
47     $(LI Cowboy it with $(B __gshared).)
48     )
49
50 $(H3 $(LNAME2 vtls, Identifying TLS variables))
51
52     $(P The first step is to find all the global variables,
53     so they can be reviewed for disposition.
54     )
55
56     $(P Given the complexity of source code, it isn't always
57     easy to identify the global variables. Since it (used to be)
58     implicit, there's no way to grep for them. It's hard
59     to be sure you've found them all.
60     )
61
62     $(P A new dmd compiler switch was added, $(B -vtls).
63     Compiling with it on will print a list of all the global
64     variables that are now defaulting to thread local storage.
65     )
66
67 ---
68 int x;
69
70 void main()
71 {
72     static int y;
73 }
74 ---
75
76 $(CONSOLE
77 dmd test $(B -vtls)
78 test.d(2): x is thread local
79 test.d(6): y is thread local
80 )
81
82 $(H3 $(LNAME2 #immutable, Switch to Immutable))
83
84     $(P Immutable data, once initialized, never changes.
85     This means that there are no synchronization issues
86     with multithreading, and so no need to put immutable data
87     into TLS. The compiler will put immutable data into
88     classic global storage, not TLS.
89     )
90
91     $(P A good chunk of global data falls into this category.
92     Just mark it as $(B immutable) and it's done.
93     )
94
95 ---
96 int[3] table = [6, 123, 0x87];
97 ---
98     $(P becomes:)
99 ---
100 immutable int[3] table = [6, 123, 0x87];
101 ---
102
103     $(P Immutability is also nice because it opens the door
104     for further compiler optimizations.
105     )
106
107 $(H3 $(LNAME2 shared, Marking As Shared))
108
109     $(P Global data that is meant to be shared among multiple
110     threads should be marked with the $(B shared) keyword:
111     )
112
113 ---
114 shared int flag;
115 ---
116
117     $(P Not only does this cause $(CODE flag) to be put into
118     classic global storage, it is also typed as being shared:
119     )
120
121 ---
122 int* p = &flags;           // error, flags is shared
123 shared(int)* q = &flags;   // ok
124 ---
125
126     $(P The $(CODE shared) type attribute is transitive (like
127     $(CODE const) and $(CODE immutable)) are. This enables
128     static checking and sharing correctness.
129     )
130
131 $(H3 $(LNAME2 __gshared, Cowboying With __gshared))
132
133     $(P Sometimes, none of the above solutions will be
134     acceptable:
135     )
136
137     $(OL
138     $(LI interfacing with C code that uses classic globals)
139     $(LI just get it working, and go back and fix it later)
140     $(LI the app is single threaded only, so no sharing issues)
141     $(LI you need every erg of performance)
142     $(LI you want to handle all the synchronization issues
143     yourself)
144     )
145
146     $(P As D is a systems language, of course there's a way to
147     do this. Use the storage class $(B __gshared):
148     )
149
150 ---
151 __gshared int x;
152
153 void main()
154 {
155     __gshared int y;
156 }
157 ---
158
159     $(P $(B __gshared) stores the variable in the classic global
160     data segment.
161     )
162
163     $(P Naturally, $(B __gshared) is not allowed in safe mode.
164     )
165
166     $(P Using $(B __gshared) makes such code easily searchable
167     when doing QA code reviews or when going back later to
168     fix any workarounds.
169     )
170
171 $(H3 $(LNAME2 #compile-errors, Compile Errors))
172
173     $(P The most common compiler error related to TLS will be:
174     )
175
176 ---
177 int x;
178 int* p = &x;
179 ---
180 $(CONSOLE
181 test.d(2): Error: non-constant expression & x
182 )
183
184     $(P While this works with classic global variables, it
185     won't work with TLS variables. The reason is because
186     TLS variables don't have a location in memory known to
187     either the linker or the loader. It's a runtime computed
188     value.)
189
190     $(P The solution is to initialize such things in
191     a static constructor.)
192
193 $(H3 $(LNAME2 link-errors, Link Errors))
194
195     $(P Sometimes you may encounter strange error messages from the linker
196     about the global variables.
197     These are nearly always caused by one module putting the variable
198     in TLS, and another putting that same variable in classic global
199     storage.
200     This can happen when linking code with libraries that were built
201     with earlier versions of dmd. Check that libphobos2.a was properly
202     replaced with the latest.
203     It can also happen when interfacing with C. C globals default
204     to being classic global, although C does support TLS declarations.
205     Make sure the corresponding D declarations match the C ones in
206     terms of TLS or classic global.
207     )
208
209 $(CCODE
210 int x;
211 extern int y;
212 __thread int z;
213 )
214
215 ---
216 extern (C)
217 {
218     extern shared int x;
219     shared int y;
220     extern int z;
221 }
222 ---
223
224 )
225
226 Macros:
227     H2=<h2>$0</h2>
228     H3=<h3>$0</h3>
229     TITLE=Migrating to Shared
230     WIKI=Migrating To Shared
Note: See TracBrowser for help on using the browser.