You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程矩阵乘法ASM实现偶发结果矩阵首行元素为0问题求助

多线程矩阵乘法ASM实现偶发第一行部分元素为0问题

我正在实现多线程矩阵乘法应用,整体功能几乎都正常,唯独ASM中的多线程逻辑存在问题。当我在乘法运算阶段启用多线程时,偶发结果矩阵第一行的部分元素为0。我尝试了所有可能的方案都没能找到错误,因此向各位求助。

首先是运行正常的C++实现代码:

void multiply(int* resultRow, int* row, int* column, int size)
{
    int* startCol = column;
    int* start = row;
    for (int i = 0; i < size; i++)
    {
        column = startCol;
        column += i;
        (*resultRow) = 0;
        row = start;
        for (int j = 0; j < size; j++)
        {
            (*resultRow) += ((*row) * (*column));
            row++;
            column += size;
        }
        resultRow++;
    }
}

该函数即使在多线程场景下也可以正常运行(resultRow是结果矩阵第i行的地址,row和columns是待乘矩阵对应行和列的地址)

以下是存在问题的ASM代码:

.CODE

;-------------------------------------------------------------------------
;-------------------------------------------------------------------------

AsmMultiplication PROC loopCount: qword, secondLoopCount: qword, startColAddress : qword, startRowAddress : qword, count : qword, matrixSize : qword                                                                                                                                                               
                        ; resultRow in RCX
                        ; rowToMultiply in RDX
                        ; colToMultiply in R8
                        ; size int R9
mov matrixSize, R9
mov loopCount, R9
mov secondLoopCount, R9
mov count, 0

mov R10, RDX
mov R9, RCX

mov startColAddress, R8
mov startRowAddress, R10

loop1:
mov R8, startColAddress             ; column = startColAddress
mov R10, startRowAddress            ; row = startRowAddress

mov RAX, count                      ; |
mov RCX, 4                          ; |
mul RCX                             ; |
add R8, RAX                         ; | column += i

xor RAX, RAX                        ; |
mov [R9], RAX                       ; (*resultRow) = 0

mov RAX, matrixSize                 ; |
mov loopCount, RAX                  ; |
pxor xmm2, xmm2                     ; | preparing for multiplying in loop2
inc count
    
            loop2:
            movq xmm0, qword ptr [R10]          ;move actual row element to vector
            movq xmm1, qword ptr [R8]           ;move actual column element to vector
            pmuludq xmm0, xmm1                  ;multiply vectors
            paddq xmm2, xmm0                    ;add result to third vector

            add R10, 4                          ; row++

            mov RAX, matrixSize                 ; |
mov RDX, 4                          ; |
mul RDX                             ; |
add R8, RAX                         ; | column += size

            mov RDX, loopCount                  ; |
            dec RDX                             ; | decrementing loop counter
            mov loopCount, RDX                  ; | 
            jnz loop2                           ; | if loopCount == 0 break

movq RAX, xmm2                      ; |
mov [R9], RAX                       ; | resultRow = rows * columns
add R9, 4                           ; | resultRows++

mov RDX, secondLoopCount            ; |
dec RDX                             ; |
mov secondLoopCount, RDX            ; |
jnz loop1                           ; | if secondLoopCount == 0 break


ret
AsmMultiplication ENDP


end

多线程调用逻辑如下:

public void ThreadedFunction(int size, int rows)
{
    unsafe
    {
        fixed (int* resultRow = &m3.matrix[rows, 0])
        fixed (int* rowToMultiply = &m1.matrix[rows, 0])
        fixed (int* colToMultiply = &m2.matrix[0, 0])
            if(Asm == false)
            {
                MatrixMultiplication.App.multiply(resultRow, rowToMultiply, colToMultiply, size);
            }
            else
            {
                MatrixMultiplication.App.AsmMultiplication(resultRow, rowToMultiply, colToMultiply, size);
            }
            
    }
}
...

for (int i = 0; i < threadsCount; i++)
{
    threads[i] = this.StartTheThread(size, rows);
    rows++;
}

问题原因

你的ASM代码不符合Windows x64调用约定,且临时变量存储方式不是线程安全的:

  • 你在PROC声明中定义的loopCount、secondLoopCount等伪参数,本质是栈上的共享存储位置,多线程同时调用函数时会互相覆盖这些计数器的取值,导致循环提前终止,最终输出值为初始的0
  • 你使用的R10、XMM2属于x64调用约定中的非易失性寄存器,你没有在函数开头做入栈保存、返回前出栈恢复的操作,会破坏调用方上下文,不同线程的寄存器值也会互相干扰
  • C++版本正常是因为编译器会自动为每个线程的函数调用分配独立栈帧,自动处理非易失性寄存器的保存恢复,所有临时变量、计数器都是线程独立的,不存在互相覆盖的问题

修复方案

  1. 函数开头按照x64调用约定分配独立栈帧,把循环计数器、临时变量存在当前函数栈帧的独立偏移位置,不要用共享的伪参数存储
  2. 把用到的非易失性寄存器(R10、XMM2等)在函数开头入栈保存,返回前弹出恢复原有值
  3. 优先用寄存器存储循环计数器,避免内存读写的线程冲突

内容的提问来源于stack exchange,提问作者Tom5821

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 01:24:04