一连几天我有麻烦了Windows 7 Ivy Bridge的系统上创建四个线程(四个核心)。 我已经创造了NASM一个简单的测试功能,如最小的,因为它可以,向人们展示。
该计划增加从0到1十亿计数器并返回结果。 多核处理,我分割它,以便芯1从0计数到250万,芯2的计数为2.5万〜500万,等
出于测试目的。 程序返回与来自每个核心的三个值的12元件阵列。 元素1-4是由CreateThread的返回线程处理; 元件5-8是线程进入测试功能(Test_fn)后,从呼叫的返回值GetCurrentThreadId; 和元件9-12是由每个线程执行的计算的结果(从startbyte计数到endbyte)。
数组返回(TestInfo)显示的CreateThread总是成功,因为前四个元素,总是包含由CreateThread的返回线程句柄(在我的测试),和元素5-8总是在进入功能Test_fn从GetCurrentThreadId返回一个值。 的问题是,元件9-12(来自每个核心的计算结果)并不总是从数学运算中Test_fn的主体返回一个值,和分布是随机的(有时芯1和4会成功,有时芯2和3只,等等)。 这意味着线程并不总是成功运行,分配给他们的计算,即使他们创建和调用Test_fn。
这是一个从Python中调用的DLL,但它可以从C或C ++调用。 它不带任何参数,并且它返回一个指针到12元件阵列测试TestInfo(如上所述)。 入口点是Main_Entry_fn,这就要求Init_Cores_fn。 线程是指出Test_fn。
所以我的问题是,为什么在线程并不总是可靠地返回从Test_fn一个值,即使线程明确要求Test_fn。
; Header Section
[BITS 64]
[default rel]
extern malloc, calloc, realloc, free
global Main_Entry_fn
export Main_Entry_fn
extern CreateThread, CloseHandle, ExitThread
extern WaitForMultipleObjects, GetCurrentThreadId
section .data align=16
const_1000000000: dq 1000000000
ThreadID: dq 0
TestInfo: times 12 dq 0
ThreadInfo: times 3 dq 0
ThreadInfo2: times 3 dq 0
ThreadInfo3: times 3 dq 0
ThreadInfo4: times 3 dq 0
ThreadHandles: times 4 dq 0
Division_Size: dq 0
Start_Byte: dq 0
End_Byte: dq 0
Return_Data_Array: times 4 dq 0
Core_Number: dq 0
section .text
; ______________________________________
Init_Cores_fn:
; Calculate the data divisions
mov rax,[const_1000000000]
mov rbx,4 ;cores
xor rdx,rdx
div rbx
mov [End_Byte],rax
mov [Division_Size],rax
mov rax,0
mov [Start_Byte],rax
; Populate the ThreadInfo arrays to pass for each core
; ThreadInfo: (1) startbyte; (2) endbyte; (3) Core_Number (0, 8, 16, 24)
mov rdi,ThreadInfo
mov rax,[Start_Byte]
mov [rdi],rax
mov rax,[End_Byte]
mov [rdi+8],rax
mov rax,[Core_Number]
mov [rdi+16],rax
call DupThreadInfo ; Create ThreadInfo arrays for cores 2-4
mov rbp,rsp ; preserve caller's stack frame
sub rsp,56 ; Shadow space (was 32)
; _____
label_0:
mov rax,[Core_Number]
cmp rax,0
jne sb2
mov rdi,ThreadInfo
jmp sb5
sb2:cmp rax,8
jne sb3
mov rdi,ThreadInfo2
jmp sb5
sb3:cmp rax,16
jne sb4
mov rdi,ThreadInfo3
jmp sb5
sb4:cmp rax,24
jne sb5
mov rdi,ThreadInfo4
sb5:
; _____
; Create Threads
mov rcx,0 ; lpThreadAttributes (Security Attributes)
mov rdx,0 ; dwStackSize
mov r8,Test_fn ; lpStartAddress (function pointer)
mov r9,rdi ; lpParameter (array of data passed to each core)
mov rax,0
mov [rsp+32],rax ; use default creation flags
mov rdi,ThreadID
mov [rsp+40],rdi ; ThreadID
call CreateThread
; Move the handle into ThreadHandles array (returned in rax)
mov rdi,ThreadHandles
mov rcx,[Core_Number]
mov [rdi+rcx],rax
mov rdi,TestInfo
mov [rdi+rcx],rax
mov rax,[Core_Number]
add rax,8
mov [Core_Number],rax
mov rbx,32 ; Four cores
cmp rax,rbx
jl label_0
; _____
; Wait
mov rcx,4 ;rax ; number of handles
mov rdx,ThreadHandles ; pointer to handles array
mov r8,0 ; wait for all threads to complete
mov r9,5000 ; milliseconds to wait
call WaitForMultipleObjects
; _____
mov rsp,rbp
jmp label_900
; ______________________________________
Test_fn:
;______
; GetCurrentThreadId
mov rdi,rcx
push rcx
call GetCurrentThreadId
mov rcx,[rdi+16] ; startbyte
mov rdi,TestInfo
mov [rdi+rcx+32],rax
pop rcx
;______
mov rdi,rcx
mov r14,[rdi] ; Start_Byte
mov r15,[rdi+8] ; End_Byte
mov r13,[rdi+16] ; Core_Number
;______
label_401:
cmp r14,r15
jge label_899
; n += 1
add r14,1
jmp label_401
;______
label_899:
mov rdi,Return_Data_Array
mov [rdi+r13],r14
mov rdi,TestInfo
mov [rdi+r13+64],r14
mov rbp,ThreadHandles
mov rax,[rbp+r13]
;mov [rdi+rbx+64],rax
call ExitThread
ret
; __________
label_900:
mov rdi,ThreadHandles
mov r8,0
label_900_01:
mov rcx,[rdi+r8]
call CloseHandle
add r8,8
cmp r8,32
jl label_900_01
mov rdi,TestInfo
mov rax,rdi
ret
; __________
; Main Entry
Main_Entry_fn:
push rdi
push rbp
call Init_Cores_fn
pop rbp
pop rdi
ret
DupThreadInfo:
mov rdi,ThreadInfo2
mov rax,8
mov [rdi+16],rax ; Core Number
mov rax,[Start_Byte]
add rax,[Division_Size]
mov [rdi],rax
mov rax,[End_Byte]
add rax,[Division_Size]
mov [rdi+8],rax
mov [Start_Byte],rax
mov rdi,ThreadInfo3
mov rax,16
mov [rdi+16],rax ; Core Number
mov rax,[Start_Byte]
mov [rdi],rax
add rax,[Division_Size]
mov [rdi+8],rax
mov [Start_Byte],rax
mov rdi,ThreadInfo4
mov rax,24
mov [rdi+16],rax ; Core Number
mov rax,[Start_Byte]
mov [rdi],rax
add rax,[Division_Size]
mov [rdi+8],rax
mov [Start_Byte],rax
ret
芯使用3-元件阵列的ThreadInfo,ThreadInfo2,ThreadInfo3和ThreadInfo4用于他们的数据。 为每个线程,它们包含开始编号,结束数,并乘以8的芯数:
0 2.5亿0
2.5亿5亿8
5亿7.5亿16
7.5亿10亿24
这里有四个独立的测试结果:
1548 1716 1688六千四百六十○分之一千七百六十八6464 6468250000000分之64720 0 10亿
1744 860 1724六千七百八十○分之一千六百六十八6784 6788 6792/0 0 0 10亿
1632 1588 1488七千○二十四分之八百七十二7028 7032 7036/0 5亿0 0
1740 1732 16846876分之15366884 6888250000000分之68800 7.5亿0
前四个数字是每个核心的线程句柄; 第二四个编号是从GetCurrentThreadId在进入Test_fn返回值,并且最后一组四个数字的是在Test_fn执行的简单的计算的结果; 它们表明内核在一些但不是所有情况下返回正确的数据。
感谢您的任何想法。