【问题标题】:Nasm - Change variable in different threadsNasm - 在不同线程中更改变量
【发布时间】:2021-06-24 21:08:20
【问题描述】:

我有一个程序,它有一个主线程和一个第二个线程。第二个线程修改一个全局变量,然后将在主线程中使用。但不知何故,我在第二个线程中所做的更改并没有显示在主线程中。

section .bss USE32
  global var
  var resd 1

section .text USE32
  ..start:
  push 0
  push 0
  push 0
  push .second
  push 0
  push 0
  call [CreateThread]
  mov eax, 1
  cmp [var], eax ; --> the content of var and '1' are not the same. Which is confusing since I set the content of var to '1' in the second thread
  ;the other code here is not important

.second:
  mov eax, 1
  mov [var], eax
  ret

(这是我在循环中创建线程的真实程序的简化;I haven't tested this exact code。)

【问题讨论】:

  • 为什么 var 的内容必须是 '1' 此时 ?

标签: multithreading winapi assembly x86 nasm


【解决方案1】:

你不要join新线程(等待它退出);没有理由假设 CreateThread 返回主线程时它已经完成(甚至完全启动)。

如果您想对线程启动开销 + 内核间延迟进行基准测试,您可以等待直到在 [var] 中看到一个非零值,然后计算需要多少次迭代。

   ...
   call  [CreateThread]
   mov   edi, 1
   cmp   [var], edi
   je   .zero_latency    ; if var already changed

   rdtsc                 ; could put an lfence before and/or after this to serialize execution
   mov  ecx, eax         ; save low half of EDX:EAX cycle count; should be short enough that the interval fits in 32 bits
   xor  esi, esi
  .spin:
   inc  esi            ; ++spin_count
   pause               ; optional, but avoids memory-order mis-speculation when var changes
   cmp  [var], edi
   jne .spin

   rdtsc
   sub  eax, ecx        ; reference cycles since CreateThread returned
   ...
 .zero_latency:         ; jump here if the value already changed before the first iteration

请注意,rdtscreference 周期而非核心时钟周期衡量,因此 turbo 很重要。如果间隔小于 2^32(例如,在参考频率为 4.2 GHz 的 CPU 上大约 1 秒,比我们预期的要长得多),则仅执行 64 位减法的低 32 位即可。

esi 是旋转计数。在循环中使用pause,您将在 Skylake 及更高版本上每 100 个周期进行一次检查,或者在早期英特尔上每 5 个周期进行一次检查。否则,每个核心时钟周期大约进行一次检查。

【讨论】:

  • 我在主线程中添加了一个循环。但是第二个线程仍然无法修改全局变量var,以便主线程可以看到新值。是否有一些关键字我必须用来告诉编译器这个变量可以被多个线程修改?例如 C 中的 volatile
  • C 中的易失性只是意味着加载或存储必须在 asm 中实际发生。当用汇编语言手写时,你已经在强迫它发生了。缓存是连贯的,因此一个线程中的存储肯定会在几百纳秒内对其他线程中的负载可见。不需要特别说明。那是why volatile works in C
  • @MenNotAtWork:如果您在 main 中的自旋循环没有退出,那么您的程序中有错误,例如也许 CreateThread 在没有实际创建另一个线程的情况下返回错误。尝试在另一个线程中添加一些其他代码,例如调用putsCreateFile,它们会产生一些可见的效果。或者只是在.second 中设置一个断点,看看它是否已经到达。
  • @MenNotAtWork:注意push second.second 不是同一个标签,. 很重要。如果您在某处有其他second: 标签,这就是您传递给 CreateThread 的内容。我认为这只是问题中的一个错字,但如果那是你的真实代码,那就是个问题。
  • 对 CreateProcess 的调用在我的真实程序中处于循环中。我简化了问题的代码。我想通过在我的原始程序中调用多个线程,我会在 var 的内容在第二个线程中被更改后再次覆盖它。
猜你喜欢
  • 2016-01-25
  • 2022-10-14
  • 2021-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多