golang之string类型变量操作的原子性

在并发场景下,string跟map一样,都是需要使用atomic包/sync包来保证读写的原子性。


str_atom.go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package main

import (
"fmt"
"time"
)

var a = "0"

func main() {

ch := make(chan string)

go func() {
i := 1

for {

if i%2 == 0 {
a = "0"
} else {
a = "aa"
}
// 如果将sleep去掉,则会读不到脏数据,原因在于编译器做了优化
time.Sleep(1 * time.Millisecond)
i++
}
}()

go func() {
for {
b := a
if b != "0" && b != "aa" {
ch <- b
}
}
}()

for i := 0; i < 10; i++ {
fmt.Println("Got strange string: ", <-ch)
}

}


按预期, ch 不可能被写入,因为 b 的值只可能是 “0” 或 “aa”.

但实际运行:

(即起两个协程,一个不停对a重新赋值,另一个选出a的值不为”0”或”aa”的,存入一个channel,并打印. 当有10次不为”0”或”aa”后,结束打印,程序运行完成)

1
2
3
4
5
6
7
8
9
10
Got strange string:  05
Got strange string: a
Got strange string: a
Got strange string: 05
Got strange string: 05
Got strange string: a
Got strange string: a
Got strange string: a
Got strange string: a
Got strange string: a

在Linux上输出为05,在Mac上05会输出为0:


b的值为什么会存在 “a”或者”05”(or”0:”)的情况 ??


这是因为,string类型并不是并发安全的.


string的内部结构:

1
2
3
4
struct {
str uintptr
len int
}

string 赋值,并不是原子操作,而是会分为两步,(其实是对上面这个struct ,Go 无法保证原子性地完成赋值)

因此可能会出现 goroutine 1 刚修改完指针(str)、还没来得及修改长度(len),goroutine 2 就读取了这个string 的情况。

str 改了、len 还没来得及改,即 str="aa",len=1, 和str="0",len=2, 对应”莫名其妙”出现的 “a”和”05”(或”0:”)


1
2
3
4
5
6
7
8
9
10
11
func main() {

var str string = "0"
p := (*struct {
str uintptr
len int
})(unsafe.Pointer(&str))

spew.Dump(p)

}

输出:

1
2
3
4
(*struct { str uintptr; len int })(0xc00008e2b0)({
str: (uintptr) 0x1101b01,
len: (int) 1
})

思考:

str="aa",len=1,变为”a”容易理解,但str="0",len=2为什么会是”05”(or“0:”)呢?


go tool compile -S -S str_atom.go 得到汇编代码:(go 1.17,arm64)

也可将源码复制到该网站,在线查看汇编

`go tool compile -S -S str_atom.go`
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
"".main<1> STEXT size=304 args=0x0 locals=0x88 funcid=0x0
0x0000 00000 (str_atom.go:10) TEXT "".main(SB), ABIInternal, $144-0
0x0000 00000 (str_atom.go:10) MOVD 16(g), R1
0x0004 00004 (str_atom.go:10) PCDATA $0, $-2
0x0004 00004 (str_atom.go:10) SUB $16, RSP, R2
0x0008 00008 (str_atom.go:10) CMP R1, R2
0x000c 00012 (str_atom.go:10) BLS 288
0x0010 00016 (str_atom.go:10) PCDATA $0, $-1
0x0010 00016 (str_atom.go:10) MOVD.W R30, -144(RSP)
0x0014 00020 (str_atom.go:10) MOVD R29, -8(RSP)
0x0018 00024 (str_atom.go:10) SUB $8, RSP, R29
0x001c 00028 (str_atom.go:10) FUNCDATA ZR, gclocals·7d2d5fca80364273fb07d5820a76fef4(SB)
0x001c 00028 (str_atom.go:10) FUNCDATA $1, gclocals·1373f50311b358236be33e875131d17d(SB)
0x001c 00028 (str_atom.go:10) FUNCDATA $2, "".main.stkobj(SB)
0x001c 00028 (str_atom.go:12) MOVD $type.chan string(SB), R0
0x0024 00036 (str_atom.go:12) MOVD R0, 8(RSP)
0x0028 00040 (str_atom.go:12) MOVD ZR, 16(RSP)
0x002c 00044 (str_atom.go:12) PCDATA $1, ZR
0x002c 00044 (str_atom.go:12) CALL runtime.makechan(SB)
0x0030 00048 (str_atom.go:12) MOVD 24(RSP), R0
0x0034 00052 (str_atom.go:12) MOVD R0, "".ch-56(SP)
0x0038 00056 (str_atom.go:14) MOVW ZR, 8(RSP)
0x003c 00060 (str_atom.go:14) MOVD $"".main.func1·f(SB), R1
0x0044 00068 (str_atom.go:14) MOVD R1, 16(RSP)
0x0048 00072 (str_atom.go:14) PCDATA $1, $1
0x0048 00072 (str_atom.go:14) CALL runtime.newproc(SB)
0x004c 00076 (str_atom.go:30) MOVD $8, R0
0x0050 00080 (str_atom.go:30) MOVW R0, 8(RSP)
0x0054 00084 (str_atom.go:30) MOVD $"".main.func2·f(SB), R0
0x005c 00092 (str_atom.go:30) MOVD R0, 16(RSP)
0x0060 00096 (str_atom.go:30) MOVD "".ch-56(SP), R0
0x0064 00100 (str_atom.go:30) MOVD R0, 24(RSP)
0x0068 00104 (str_atom.go:30) CALL runtime.newproc(SB)
0x006c 00108 (str_atom.go:30) MOVD ZR, R0
0x0070 00112 (str_atom.go:39) JMP 268
0x0074 00116 (str_atom.go:39) MOVD R0, "".i-64(SP)
0x0078 00120 (str_atom.go:40) STP (ZR, ZR), ""..autotmp_9-48(SP)
0x007c 00124 (str_atom.go:40) MOVD "".ch-56(SP), R0
0x0080 00128 (str_atom.go:40) MOVD R0, 8(RSP)
0x0084 00132 (str_atom.go:40) MOVD $""..autotmp_9-48(SP), R1
0x0088 00136 (str_atom.go:40) MOVD R1, 16(RSP)
0x008c 00140 (str_atom.go:40) PCDATA $1, $2
0x008c 00140 (str_atom.go:40) CALL runtime.chanrecv1(SB)
0x0090 00144 (str_atom.go:40) MOVD ""..autotmp_9-48(SP), R0
0x0094 00148 (str_atom.go:40) MOVD ""..autotmp_9-40(SP), R1
0x0098 00152 (str_atom.go:40) MOVD R0, 8(RSP)
0x009c 00156 (str_atom.go:40) MOVD R1, 16(RSP)
0x00a0 00160 (str_atom.go:40) PCDATA $1, $1
0x00a0 00160 (str_atom.go:40) CALL runtime.convTstring(SB)
0x00a4 00164 (str_atom.go:40) MOVD 24(RSP), R0
0x00a8 00168 (str_atom.go:40) STP (ZR, ZR), ""..autotmp_14-32(SP)
0x00ac 00172 (str_atom.go:40) STP (ZR, ZR), ""..autotmp_14-16(SP)
0x00b0 00176 (str_atom.go:40) MOVD $type.string(SB), R1
0x00b8 00184 (str_atom.go:40) MOVD R1, ""..autotmp_14-32(SP)
0x00bc 00188 (str_atom.go:40) MOVD $""..stmp_0(SB), R2
0x00c4 00196 (str_atom.go:40) MOVD R2, ""..autotmp_14-24(SP)
0x00c8 00200 (str_atom.go:40) MOVD R1, ""..autotmp_14-16(SP)
0x00cc 00204 (str_atom.go:40) MOVD R0, ""..autotmp_14-8(SP)
0x00d0 00208 (<unknown line number>) NOP
0x00d0 00208 (<unknown line number>) PCDATA $0, $-3
0x00d0 00208 (str_atom.go:40) MOVD os.Stdout(SB), R0
0x00dc 00220 (str_atom.go:40) PCDATA $0, $-1
0x00dc 00220 (str_atom.go:40) MOVD $go.itab.*os.File,io.Writer(SB), R3
0x00e4 00228 (str_atom.go:40) MOVD R3, 8(RSP)
0x00e8 00232 (str_atom.go:40) MOVD R0, 16(RSP)
0x00ec 00236 (str_atom.go:40) MOVD $""..autotmp_14-32(SP), R0
0x00f0 00240 (str_atom.go:40) MOVD R0, 24(RSP)
0x00f4 00244 (str_atom.go:40) MOVD $2, R0
0x00f8 00248 (str_atom.go:40) MOVD R0, 32(RSP)
0x00fc 00252 (str_atom.go:40) MOVD R0, 40(RSP)
0x0100 00256 (str_atom.go:40) CALL fmt.Fprintln(SB)
0x0104 00260 (str_atom.go:39) MOVD "".i-64(SP), R0
0x0108 00264 (str_atom.go:39) ADD $1, R0, R0
0x010c 00268 (str_atom.go:39) CMP $10, R0
0x0110 00272 (str_atom.go:39) BLT 116
0x0114 00276 (str_atom.go:43) PCDATA $1, $-1
0x0114 00276 (str_atom.go:43) MOVD -8(RSP), R29
0x0118 00280 (str_atom.go:43) MOVD.P 144(RSP), R30
0x011c 00284 (str_atom.go:43) RET (R30)
0x0120 00288 (str_atom.go:43) NOP
0x0120 00288 (str_atom.go:10) PCDATA $1, $-1
0x0120 00288 (str_atom.go:10) PCDATA $0, $-2
0x0120 00288 (str_atom.go:10) MOVD R30, R3
0x0124 00292 (str_atom.go:10) CALL runtime.morestack_noctxt(SB)
0x0128 00296 (str_atom.go:10) PCDATA $0, $-1
0x0128 00296 (str_atom.go:10) JMP 0
0x0000 81 0b 40 f9 e2 43 00 d1 5f 00 01 eb a9 08 00 54 ..@..C.._......T
0x0010 fe 0f 17 f8 fd 83 1f f8 fd 23 00 d1 00 00 00 90 .........#......
0x0020 00 00 00 91 e0 07 00 f9 ff 0b 00 f9 00 00 00 94 ................
0x0030 e0 0f 40 f9 e0 2b 00 f9 ff 0b 00 b9 01 00 00 90 ..@..+..........
0x0040 21 00 00 91 e1 0b 00 f9 00 00 00 94 e0 03 7d b2 !.............}.
0x0050 e0 0b 00 b9 00 00 00 90 00 00 00 91 e0 0b 00 f9 ................
0x0060 e0 2b 40 f9 e0 0f 00 f9 00 00 00 94 00 00 80 d2 .+@.............
0x0070 27 00 00 14 e0 27 00 f9 ff ff 05 a9 e0 2b 40 f9 '....'.......+@.
0x0080 e0 07 00 f9 e1 63 01 91 e1 0b 00 f9 00 00 00 94 .....c..........
0x0090 e0 2f 40 f9 e1 33 40 f9 e0 07 00 f9 e1 0b 00 f9 ./@..3@.........
0x00a0 00 00 00 94 e0 0f 40 f9 ff ff 06 a9 ff ff 07 a9 ......@.........
0x00b0 01 00 00 90 21 00 00 91 e1 37 00 f9 02 00 00 90 ....!....7......
0x00c0 42 00 00 91 e2 3b 00 f9 e1 3f 00 f9 e0 43 00 f9 B....;...?...C..
0x00d0 1b 00 00 90 7b 03 00 91 60 03 40 f9 03 00 00 90 ....{...`.@.....
0x00e0 63 00 00 91 e3 07 00 f9 e0 0b 00 f9 e0 a3 01 91 c...............
0x00f0 e0 0f 00 f9 e0 03 7f b2 e0 13 00 f9 e0 17 00 f9 ................
0x0100 00 00 00 94 e0 27 40 f9 00 04 00 91 1f 28 00 f1 .....'@......(..
0x0110 2b fb ff 54 fd 83 5f f8 fe 07 49 f8 c0 03 5f d6 +..T.._...I..._.
0x0120 e3 03 1e aa 00 00 00 94 b6 ff ff 17 00 00 00 00 ................
rel 0+0 t=24 type.string<0>+0
rel 0+0 t=24 type.string<0>+0
rel 0+0 t=24 type.*os.File<0>+0
rel 28+8 t=3 type.chan string<0>+0
rel 44+4 t=9 runtime.makechan<1>+0
rel 60+8 t=3 "".main.func1·f<0>+0
rel 72+4 t=9 runtime.newproc<1>+0
rel 84+8 t=3 "".main.func2·f<0>+0
rel 104+4 t=9 runtime.newproc<1>+0
rel 140+4 t=9 runtime.chanrecv1<1>+0
rel 160+4 t=9 runtime.convTstring<1>+0
rel 176+8 t=3 type.string<0>+0
rel 188+8 t=3 ""..stmp_0<0>+0
rel 208+8 t=3 os.Stdout<0>+0
rel 220+8 t=3 go.itab.*os.File,io.Writer<0>+0
rel 256+4 t=9 fmt.Fprintln<1>+0
rel 292+4 t=9 runtime.morestack_noctxt<0>+0
"".main.func2<1> STEXT size=144 args=0x8 locals=0x28 funcid=0x0
0x0000 00000 (str_atom.go:30) TEXT "".main.func2(SB), ABIInternal, $48-8
0x0000 00000 (str_atom.go:30) MOVD 16(g), R1
0x0004 00004 (str_atom.go:30) PCDATA $0, $-2
0x0004 00004 (str_atom.go:30) MOVD RSP, R2
0x0008 00008 (str_atom.go:30) CMP R1, R2
0x000c 00012 (str_atom.go:30) BLS 128
0x0010 00016 (str_atom.go:30) PCDATA $0, $-1
0x0010 00016 (str_atom.go:30) MOVD.W R30, -48(RSP)
0x0014 00020 (str_atom.go:30) MOVD R29, -8(RSP)
0x0018 00024 (str_atom.go:30) SUB $8, RSP, R29
0x001c 00028 (str_atom.go:30) FUNCDATA ZR, gclocals·1a65e721a2ccc325b382662e7ffee780(SB)
0x001c 00028 (str_atom.go:30) FUNCDATA $1, gclocals·2589ca35330fc0fce83503f4569854a0(SB)
0x001c 00028 (str_atom.go:30) FUNCDATA $2, "".main.func2.stkobj(SB)
0x001c 00028 (str_atom.go:30) FUNCDATA $5, "".main.func2.arginfo1(SB)
0x001c 00028 (str_atom.go:30) PCDATA $0, $-3
0x001c 00028 (str_atom.go:32) MOVD "".a(SB), R0
0x0028 00040 (str_atom.go:32) PCDATA $0, $-4
0x0028 00040 (str_atom.go:32) MOVD "".a+8(SB), R1
0x0034 00052 (str_atom.go:32) PCDATA $0, $-1
0x0034 00052 (str_atom.go:33) CMP $1, R1
0x0038 00056 (str_atom.go:33) BNE 72
0x003c 00060 (str_atom.go:33) MOVBU (R0), R2
0x0040 00064 (str_atom.go:33) CMPW $206158430256, R2
0x0044 00068 (str_atom.go:33) BEQ 28
0x0048 00072 (str_atom.go:33) CMP $2, R1
0x004c 00076 (str_atom.go:33) BNE 96
0x0050 00080 (str_atom.go:33) MOVHU (R0), R2
0x0054 00084 (str_atom.go:33) PCDATA $0, $-3
0x0054 00084 (str_atom.go:33) CMPW $107069239746913, R2
0x005c 00092 (str_atom.go:33) PCDATA $0, $-1
0x005c 00092 (str_atom.go:33) BEQ 28
0x0060 00096 (str_atom.go:34) MOVD R0, ""..autotmp_3-16(SP)
0x0064 00100 (str_atom.go:34) MOVD R1, ""..autotmp_3-8(SP)
0x0068 00104 (str_atom.go:34) MOVD "".ch(FP), R0
0x006c 00108 (str_atom.go:34) MOVD R0, 8(RSP)
0x0070 00112 (str_atom.go:34) MOVD $""..autotmp_3-16(SP), R1
0x0074 00116 (str_atom.go:34) MOVD R1, 16(RSP)
0x0078 00120 (str_atom.go:34) PCDATA $1, ZR
0x0078 00120 (str_atom.go:34) CALL runtime.chansend1(SB)
0x007c 00124 (str_atom.go:34) JMP 28
0x0080 00128 (str_atom.go:34) NOP
0x0080 00128 (str_atom.go:30) PCDATA $1, $-1
0x0080 00128 (str_atom.go:30) PCDATA $0, $-2
0x0080 00128 (str_atom.go:30) MOVD R30, R3
0x0084 00132 (str_atom.go:30) CALL runtime.morestack_noctxt(SB)
0x0088 00136 (str_atom.go:30) PCDATA $0, $-1
0x0088 00136 (str_atom.go:30) JMP 0
0x0000 81 0b 40 f9 e2 03 00 91 5f 00 01 eb a9 03 00 54 ..@....._......T
0x0010 fe 0f 1d f8 fd 83 1f f8 fd 23 00 d1 1b 00 00 90 .........#......
0x0020 7b 03 00 91 60 03 40 f9 1b 00 00 90 7b 03 00 91 {...`.@.....{...
0x0030 61 03 40 f9 3f 04 00 f1 81 00 00 54 02 00 40 39 a.@.?......T..@9
0x0040 5f c0 00 71 c0 fe ff 54 3f 08 00 f1 a1 00 00 54 _..q...T?......T
0x0050 02 00 40 79 3b 2c 8c 52 5f 00 1b 6b 00 fe ff 54 ..@y;,.R_..k...T
0x0060 e0 0f 00 f9 e1 13 00 f9 e0 1f 40 f9 e0 07 00 f9 ..........@.....
0x0070 e1 63 00 91 e1 0b 00 f9 00 00 00 94 e8 ff ff 17 .c..............
0x0080 e3 03 1e aa 00 00 00 94 de ff ff 17 00 00 00 00 ................
rel 28+8 t=3 "".a<0>+0
rel 40+8 t=3 "".a<0>+8
rel 120+4 t=9 runtime.chansend1<1>+0
rel 132+4 t=9 runtime.morestack_noctxt<0>+0
"".main.func1<1> STEXT size=240 args=0x0 locals=0x18 funcid=0x0
0x0000 00000 (str_atom.go:14) TEXT "".main.func1(SB), ABIInternal, $32-0
0x0000 00000 (str_atom.go:14) MOVD 16(g), R1
0x0004 00004 (str_atom.go:14) PCDATA $0, $-2
0x0004 00004 (str_atom.go:14) MOVD RSP, R2
0x0008 00008 (str_atom.go:14) CMP R1, R2
0x000c 00012 (str_atom.go:14) BLS 228
0x0010 00016 (str_atom.go:14) PCDATA $0, $-1
0x0010 00016 (str_atom.go:14) MOVD.W R30, -32(RSP)
0x0014 00020 (str_atom.go:14) MOVD R29, -8(RSP)
0x0018 00024 (str_atom.go:14) SUB $8, RSP, R29
0x001c 00028 (str_atom.go:14) FUNCDATA ZR, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x001c 00028 (str_atom.go:14) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x001c 00028 (str_atom.go:14) MOVD $1, R0
0x0020 00032 (str_atom.go:17) JMP 60
0x0024 00036 (str_atom.go:25) MOVD $1000000, R0
0x002c 00044 (str_atom.go:25) MOVD R0, 8(RSP)
0x0030 00048 (str_atom.go:25) PCDATA $1, ZR
0x0030 00048 (str_atom.go:25) CALL time.Sleep(SB)
0x0034 00052 (str_atom.go:26) MOVD "".i-8(SP), R0
0x0038 00056 (str_atom.go:26) ADD $1, R0, R0
0x003c 00060 (str_atom.go:19) MOVD R0, "".i-8(SP)
0x0040 00064 (str_atom.go:19) TBNZ ZR, R0, 148
0x0044 00068 (str_atom.go:20) MOVD $1, R1
0x0048 00072 (str_atom.go:20) PCDATA $0, $-3
0x0048 00072 (str_atom.go:20) MOVD R1, "".a+8(SB)
0x0054 00084 (str_atom.go:20) PCDATA $0, $-1
0x0054 00084 (str_atom.go:20) PCDATA ZR, $-2
0x0054 00084 (str_atom.go:20) MOVWU runtime.writeBarrier(SB), R4
0x0060 00096 (str_atom.go:20) CBNZW R4, 124
0x0064 00100 (str_atom.go:20) MOVD $go.string."0"(SB), R2
0x006c 00108 (str_atom.go:20) MOVD R2, "".a(SB)
0x0078 00120 (str_atom.go:20) JMP 36
0x007c 00124 (str_atom.go:20) MOVD $"".a(SB), R2
0x0084 00132 (str_atom.go:20) MOVD $go.string."0"(SB), R3
0x008c 00140 (str_atom.go:20) CALL runtime.gcWriteBarrier(SB)
0x0090 00144 (str_atom.go:20) JMP 36
0x0094 00148 (str_atom.go:22) PCDATA ZR, $-1
0x0094 00148 (str_atom.go:22) MOVD $2, R1
0x0098 00152 (str_atom.go:22) PCDATA $0, $-4
0x0098 00152 (str_atom.go:22) MOVD R1, "".a+8(SB)
0x00a4 00164 (str_atom.go:22) PCDATA $0, $-1
0x00a4 00164 (str_atom.go:22) PCDATA ZR, $-2
0x00a4 00164 (str_atom.go:22) MOVWU runtime.writeBarrier(SB), R4
0x00b0 00176 (str_atom.go:22) CBNZW R4, 204
0x00b4 00180 (str_atom.go:22) MOVD $go.string."aa"(SB), R2
0x00bc 00188 (str_atom.go:22) MOVD R2, "".a(SB)
0x00c8 00200 (str_atom.go:22) JMP 36
0x00cc 00204 (str_atom.go:22) MOVD $"".a(SB), R2
0x00d4 00212 (str_atom.go:22) MOVD $go.string."aa"(SB), R3
0x00dc 00220 (str_atom.go:22) CALL runtime.gcWriteBarrier(SB)
0x00e0 00224 (str_atom.go:22) JMP 36
0x00e4 00228 (str_atom.go:22) NOP
0x00e4 00228 (str_atom.go:14) PCDATA $1, $-1
0x00e4 00228 (str_atom.go:14) PCDATA $0, $-2
0x00e4 00228 (str_atom.go:14) MOVD R30, R3
0x00e8 00232 (str_atom.go:14) CALL runtime.morestack_noctxt(SB)
0x00ec 00236 (str_atom.go:14) PCDATA $0, $-1
0x00ec 00236 (str_atom.go:14) JMP 0
0x0000 81 0b 40 f9 e2 03 00 91 5f 00 01 eb c9 06 00 54 ..@....._......T
0x0010 fe 0f 1e f8 fd 83 1f f8 fd 23 00 d1 e0 03 40 b2 .........#....@.
0x0020 07 00 00 14 00 48 88 d2 e0 01 a0 f2 e0 07 00 f9 .....H..........
0x0030 00 00 00 94 e0 0b 40 f9 00 04 00 91 e0 0b 00 f9 ......@.........
0x0040 a0 02 00 37 e1 03 40 b2 1b 00 00 90 7b 03 00 91 ...7..@.....{...
0x0050 61 03 00 f9 1b 00 00 90 7b 03 00 91 64 03 40 b9 a.......{...d.@.
0x0060 e4 00 00 35 02 00 00 90 42 00 00 91 1b 00 00 90 ...5....B.......
0x0070 7b 03 00 91 62 03 00 f9 eb ff ff 17 02 00 00 90 {...b...........
0x0080 42 00 00 91 03 00 00 90 63 00 00 91 00 00 00 94 B.......c.......
0x0090 e5 ff ff 17 e1 03 7f b2 1b 00 00 90 7b 03 00 91 ............{...
0x00a0 61 03 00 f9 1b 00 00 90 7b 03 00 91 64 03 40 b9 a.......{...d.@.
0x00b0 e4 00 00 35 02 00 00 90 42 00 00 91 1b 00 00 90 ...5....B.......
0x00c0 7b 03 00 91 62 03 00 f9 d7 ff ff 17 02 00 00 90 {...b...........
0x00d0 42 00 00 91 03 00 00 90 63 00 00 91 00 00 00 94 B.......c.......
0x00e0 d1 ff ff 17 e3 03 1e aa 00 00 00 94 c5 ff ff 17 ................
rel 48+4 t=9 time.Sleep<1>+0
rel 72+8 t=3 "".a<0>+8
rel 84+8 t=3 runtime.writeBarrier<0>+0
rel 100+8 t=3 go.string."0"<0>+0
rel 108+8 t=3 "".a<0>+0
rel 124+8 t=3 "".a<0>+0
rel 132+8 t=3 go.string."0"<0>+0
rel 140+4 t=9 runtime.gcWriteBarrier<1>+0
rel 152+8 t=3 "".a<0>+8
rel 164+8 t=3 runtime.writeBarrier<0>+0
rel 180+8 t=3 go.string."aa"<0>+0
rel 188+8 t=3 "".a<0>+0
rel 204+8 t=3 "".a<0>+0
rel 212+8 t=3 go.string."aa"<0>+0
rel 220+4 t=9 runtime.gcWriteBarrier<1>+0
rel 232+4 t=9 runtime.morestack_noctxt<0>+0
os.(*File).close<1> STEXT dupok size=32 args=0x18 locals=0x0 funcid=0x0 leaf
0x0000 00000 (<autogenerated>:1) TEXT os.(*File).close(SB), DUPOK|LEAF|NOFRAME|ABIInternal, $0-24
0x0000 00000 (<autogenerated>:1) FUNCDATA ZR, gclocals·e6397a44f8e1b6e77d0f200b4fba5269(SB)
0x0000 00000 (<autogenerated>:1) FUNCDATA $1, gclocals·69c1753bd5f81501d95132d08af04464(SB)
0x0000 00000 (<autogenerated>:1) FUNCDATA $5, os.(*File).close.arginfo1(SB)
0x0000 00000 (<autogenerated>:1) MOVD ""..this(FP), R0
0x0004 00004 (<autogenerated>:1) MOVD (R0), R0
0x0008 00008 (<autogenerated>:1) MOVD R0, ""..this(FP)
0x000c 00012 (<autogenerated>:1) STP (ZR, ZR), "".~r0+8(FP)
0x0010 00016 (<autogenerated>:1) JMP os.(*file).close(SB)
0x0000 e0 07 40 f9 00 00 40 f9 e0 07 00 f9 ff 7f 01 a9 ..@...@.........
0x0010 00 00 00 14 00 00 00 00 00 00 00 00 00 00 00 00 ................
rel 16+4 t=9 os.(*file).close<1>+0
go.cuinfo.packagename.<0> SDWARFCUINFO dupok size=0
0x0000 6d 61 69 6e main
go.string."0"<0> SRODATA dupok size=1
0x0000 30 0
""..inittask<0> SNOPTRDATA size=40
0x0000 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................
0x0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0020 00 00 00 00 00 00 00 00 ........
rel 24+8 t=1 fmt..inittask<0>+0
rel 32+8 t=1 time..inittask<0>+0
go.info.fmt.Println$abstract<0> SDWARFABSFCN dupok size=42
0x0000 04 66 6d 74 2e 50 72 69 6e 74 6c 6e 00 01 01 11 .fmt.Println....
0x0010 61 00 00 00 00 00 00 11 6e 00 01 00 00 00 00 11 a.......n.......
0x0020 65 72 72 00 01 00 00 00 00 00 err.......
rel 0+0 t=23 type.[]interface {}<0>+0
rel 0+0 t=23 type.error<0>+0
rel 0+0 t=23 type.int<0>+0
rel 19+4 t=31 go.info.[]interface {}<0>+0
rel 27+4 t=31 go.info.int<0>+0
rel 37+4 t=31 go.info.error<0>+0
go.string."Got strange string: "<0> SRODATA dupok size=20
0x0000 47 6f 74 20 73 74 72 61 6e 67 65 20 73 74 72 69 Got strange stri
0x0010 6e 67 3a 20 ng:
go.string."aa"<0> SRODATA dupok size=2
0x0000 61 61 aa
"".a<0> SDATA size=16
0x0000 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................
rel 0+8 t=1 go.string."0"<0>+0
""..stmp_0<0> SRODATA static size=16
0x0000 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 00 ................
rel 0+8 t=1 go.string."Got strange string: "<0>+0
runtime.nilinterequal·f<0> SRODATA dupok size=8
0x0000 00 00 00 00 00 00 00 00 ........
rel 0+8 t=1 runtime.nilinterequal<1>+0
runtime.memequal64·f<0> SRODATA dupok size=8
0x0000 00 00 00 00 00 00 00 00 ........
rel 0+8 t=1 runtime.memequal64<1>+0
runtime.gcbits.01<0> SRODATA dupok size=1
0x0000 01 .
type..namedata.*interface {}-<0> SRODATA dupok size=15
0x0000 00 0d 2a 69 6e 74 65 72 66 61 63 65 20 7b 7d ..*interface {}
type.*interface {}<0> SRODATA dupok size=56
0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................
0x0010 4f 0f 96 9d 08 08 08 36 00 00 00 00 00 00 00 00 O......6........
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030 00 00 00 00 00 00 00 00 ........
rel 24+8 t=1 runtime.memequal64·f<0>+0
rel 32+8 t=1 runtime.gcbits.01<0>+0
rel 40+4 t=5 type..namedata.*interface {}-<0>+0
rel 48+8 t=1 type.interface {}<0>+0
runtime.gcbits.02<0> SRODATA dupok size=1
0x0000 02 .
type.interface {}<0> SRODATA dupok size=80
0x0000 10 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 ................
0x0010 e7 57 a0 18 02 08 08 14 00 00 00 00 00 00 00 00 .W..............
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
rel 24+8 t=1 runtime.nilinterequal·f<0>+0
rel 32+8 t=1 runtime.gcbits.02<0>+0
rel 40+4 t=5 type..namedata.*interface {}-<0>+0
rel 44+4 t=-32763 type.*interface {}<0>+0
rel 56+8 t=1 type.interface {}<0>+80
type..namedata.*[]interface {}-<0> SRODATA dupok size=17
0x0000 00 0f 2a 5b 5d 69 6e 74 65 72 66 61 63 65 20 7b ..*[]interface {
0x0010 7d }
type.*[]interface {}<0> SRODATA dupok size=56
0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................
0x0010 f3 04 9a e7 08 08 08 36 00 00 00 00 00 00 00 00 .......6........
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030 00 00 00 00 00 00 00 00 ........
rel 24+8 t=1 runtime.memequal64·f<0>+0
rel 32+8 t=1 runtime.gcbits.01<0>+0
rel 40+4 t=5 type..namedata.*[]interface {}-<0>+0
rel 48+8 t=1 type.[]interface {}<0>+0
type.[]interface {}<0> SRODATA dupok size=56
0x0000 18 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................
0x0010 70 93 ea 2f 02 08 08 17 00 00 00 00 00 00 00 00 p../............
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030 00 00 00 00 00 00 00 00 ........
rel 32+8 t=1 runtime.gcbits.01<0>+0
rel 40+4 t=5 type..namedata.*[]interface {}-<0>+0
rel 44+4 t=-32763 type.*[]interface {}<0>+0
rel 48+8 t=1 type.interface {}<0>+0
type..namedata.*chan string-<0> SRODATA dupok size=14
0x0000 00 0c 2a 63 68 61 6e 20 73 74 72 69 6e 67 ..*chan string
type.*chan string<0> SRODATA dupok size=56
0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................
0x0010 f4 25 61 85 08 08 08 36 00 00 00 00 00 00 00 00 .%a....6........
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030 00 00 00 00 00 00 00 00 ........
rel 24+8 t=1 runtime.memequal64·f<0>+0
rel 32+8 t=1 runtime.gcbits.01<0>+0
rel 40+4 t=5 type..namedata.*chan string-<0>+0
rel 48+8 t=1 type.chan string<0>+0
type.chan string<0> SRODATA dupok size=64
0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................
0x0010 8d 9e 8b c9 0a 08 08 32 00 00 00 00 00 00 00 00 .......2........
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 ................
rel 24+8 t=1 runtime.memequal64·f<0>+0
rel 32+8 t=1 runtime.gcbits.01<0>+0
rel 40+4 t=5 type..namedata.*chan string-<0>+0
rel 44+4 t=-32763 type.*chan string<0>+0
rel 48+8 t=1 type.string<0>+0
runtime.gcbits.0a<0> SRODATA dupok size=1
0x0000 0a .
go.itab.*os.File,io.Writer<0> SRODATA dupok size=32
0x0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0010 44 b5 f3 33 00 00 00 00 00 00 00 00 00 00 00 00 D..3............
rel 0+8 t=1 type.io.Writer<0>+0
rel 8+8 t=1 type.*os.File<0>+0
rel 24+8 t=-32767 os.(*File).Write<1>+0
type..importpath.fmt.<0> SRODATA dupok size=5
0x0000 00 03 66 6d 74 ..fmt
type..importpath.time.<0> SRODATA dupok size=6
0x0000 00 04 74 69 6d 65 ..time
"".main.func1·f<0> SRODATA dupok size=8
0x0000 00 00 00 00 00 00 00 00 ........
rel 0+8 t=1 "".main.func1<1>+0
"".main.func2·f<0> SRODATA dupok size=8
0x0000 00 00 00 00 00 00 00 00 ........
rel 0+8 t=1 "".main.func2<1>+0
gclocals·7d2d5fca80364273fb07d5820a76fef4<0> SRODATA dupok size=8
0x0000 03 00 00 00 00 00 00 00 ........
gclocals·1373f50311b358236be33e875131d17d<0> SRODATA dupok size=11
0x0000 03 00 00 00 07 00 00 00 00 01 03 ...........
"".main.stkobj<0> SRODATA static size=56
0x0000 02 00 00 00 00 00 00 00 d0 ff ff ff 10 00 00 00 ................
0x0010 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0020 e0 ff ff ff 20 00 00 00 20 00 00 00 00 00 00 00 .... ... .......
0x0030 00 00 00 00 00 00 00 00 ........
rel 24+8 t=1 runtime.gcbits.01<0>+0
rel 48+8 t=1 runtime.gcbits.0a<0>+0
gclocals·1a65e721a2ccc325b382662e7ffee780<0> SRODATA dupok size=10
0x0000 02 00 00 00 01 00 00 00 01 00 ..........
gclocals·2589ca35330fc0fce83503f4569854a0<0> SRODATA dupok size=10
0x0000 02 00 00 00 02 00 00 00 00 00 ..........
"".main.func2.stkobj<0> SRODATA static size=32
0x0000 01 00 00 00 00 00 00 00 f0 ff ff ff 10 00 00 00 ................
0x0010 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
rel 24+8 t=1 runtime.gcbits.01<0>+0
"".main.func2.arginfo1<0> SRODATA static dupok size=3
0x0000 00 08 ff ...
gclocals·33cdeccccebe80329f1fdbee7f5874cb<0> SRODATA dupok size=8
0x0000 01 00 00 00 00 00 00 00 ........
gclocals·e6397a44f8e1b6e77d0f200b4fba5269<0> SRODATA dupok size=10
0x0000 02 00 00 00 03 00 00 00 01 00 ..........
gclocals·69c1753bd5f81501d95132d08af04464<0> SRODATA dupok size=8
0x0000 02 00 00 00 00 00 00 00 ........
os.(*File).close.arginfo1<0> SRODATA static dupok size=3
0x0000 00 08 ff ...




参考:

Golang string变量操作的原子性

go 字符串string的并发读写的一个坑

golang: 常用数据类型底层结构分析

你不知道的 Go 之 string

更多相关:

golang 中 int加一是原子性吗

golang int并发安全 atom

姊妹篇:

golang之map并发访问

golang之slice并发访问




str="aa",len=1,变为”a”容易理解,但str="0",len=2为什么会是”05”呢?


string在底层的存储方式如下:

1
2
3
4
type StringHeader struct {
Data uintptr // 内容的指针地址
Len int // 长度
}

在上面的并发读写过程中,即发生了

1
2
3
4
5
6
7
8
9
s1 := StringHeader{
Data: `指向"aa"的那个内存地址,记为x`,
Len: 1,
}

s2 := StringHeader{
Data: `指向"0"的那个内存地址,记为y`,
Len: 2,
}

可以打印出y的内容,就一目了然了


先看如下例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import (
"encoding/hex"
"fmt"
"strings"
"unsafe"
)

func main() {

demoStr := "abcdefghijklmnop1234567887654321"
dump("demoStr", &demoStr)

}

func dump(name string, strPtr *string) {
// 分隔符
fmt.Println(strings.Repeat("-", 30))

// 打印strPtr这个指针类型的变量的内存地址
fmt.Printf("&%s:%p\n", name, strPtr)
// 强制转换为16字节的byte数组 (*[0x10]byte)(unsafe.Pointer(strPtr)),是个指针类型。再用*取指针内容; 然后将数组转为切片,[:]
fmt.Println(hex.Dump((*(*[0x10]byte)(unsafe.Pointer(strPtr)))[:]))

// 获取上面这个指针所指向的内存地址
p := *(*int)(unsafe.Pointer(strPtr)) // 当成int型(需要C经验更好理解)
fmt.Printf("%s:0x%x\n", name, p)
fmt.Println(hex.Dump((*(*[0x20]byte)(unsafe.Pointer(uintptr(p))))[:]))

}

输出为:

1
2
3
4
5
6
7
------------------------------
&demoStr:0x14000010240
00000000 82 34 ea 00 01 00 00 00 20 00 00 00 00 00 00 00 |.4...... .......|

demoStr:0x100ea3482
00000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 |abcdefghijklmnop|
00000010 31 32 33 34 35 36 37 38 38 37 36 35 34 33 32 31 |1234567887654321|

(内存地址对应的内容也是16进制格式)

比对ASCII码表

可以看出一一对应


而对于”0”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import (
"encoding/hex"
"fmt"
"strings"
"unsafe"
)

func main() {

demoStr := "0"
dump("demoStr", &demoStr)

}

func dump(name string, strPtr *string) {
// 分隔符
fmt.Println(strings.Repeat("-", 30))

// 打印strPtr这个指针类型的变量的内存地址
fmt.Printf("&%s:%p\n", name, strPtr)
// 强制转换为16字节的byte数组 (*[0x10]byte)(unsafe.Pointer(strPtr)),是个指针类型。再用*取指针内容; 然后将数组转为切片,[:]
fmt.Println(hex.Dump((*(*[0x10]byte)(unsafe.Pointer(strPtr)))[:]))

// 获取上面这个指针所指向的内存地址
p := *(*int)(unsafe.Pointer(strPtr)) // 当成int型(需要C经验更好理解)
fmt.Printf("%s:0x%x\n", name, p)
fmt.Println(hex.Dump((*(*[0x20]byte)(unsafe.Pointer(uintptr(p))))[:]))

}

输出:

1
2
3
4
5
6
7
8
------------------------------
&demoStr:0x14000110060
00000000 a7 a6 d1 02 01 00 00 00 01 00 00 00 00 00 00 00 |................|

demoStr:0x102d1a6a7
00000000 30 3a 3c 3d 3e 43 4c 4d 50 53 55 5a 5b 5d 5f 60 |0:<=>CLMPSUZ[]_`|
00000010 68 6d 73 7b 7d 20 2b 20 40 20 50 20 5b 25 21 28 |hms{} + @ P [%!(|

可以看出,当长度为2,但实际存的内容为1时是咋填充的

在该场景下,对于Mac,会填充为0x3a,即对应:

对于Linux,则会填充0x35,即对应5