首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >gdb:将scheduler_locking设置为始终会导致死锁

gdb:将scheduler_locking设置为始终会导致死锁
EN

Stack Overflow用户
提问于 2020-01-06 19:50:23
回答 1查看 365关注 0票数 0

我使用gdb调试C程序使用dlopen()和dlsym()加载的共享对象。共享对象是用NASM编写的,它使用矮小调试符号进行编译。我在Ubuntu 18.04上跑。

我希望每个线程在被创建之后完全停止,这样我就可以在继续之前创建所有四个线程。因此,我以"set调度程序锁定“或"set调度程序锁定步骤”启动调试会话。

正如我所理解的,gdb命令"set调度程序锁定“应该允许我创建一个线程,然后切换回线程1(主线程)并创建另一个线程,等等,直到所有线程都创建完毕。

在NASM代码中,我在标签Test_fn:(参见下面的代码)设置了一个断点。当线程到达该断点时,它将停止(这是线程创建后的第一个断点)。然后我切换到后台线程1(主线程),并“继续”实例化下一个线程(主线程仍然在label_0部分的Init_Cores)。线程1将执行代码(如果我通过它的话),但是在创建下一个线程之前的某个时候,它会死锁,并且总是死锁。

我也尝试过单步执行线程创建(避免“继续”),但仍然存在死锁。

根据在How to continue one thread at a time when debugging a multithreaded program in GDB?工作的俄国人的回答,这种情况是可以发生的,但他并没有说这一切都会发生。无论我使用"set调度程序锁定“还是"set调度程序锁定步骤”,我都会出现死锁。

也许这是因为它是一个共享对象,但是其他的东西都与共享对象一起工作,所以我不认为这是问题所在。

这是NASM代码。同样的问题也适用于C或C++代码,特别是当我到达新线程上的断点时,为什么gdb死锁,然后切换回线程1继续创建线程。当调度程序锁定启动时,线程2(第一个创建的线程)应该停止.

代码语言:javascript
复制
; Header Section
[BITS 64]

[default rel]

global Main_Entry_fn
extern pthread_create, pthread_join, pthread_exit, pthread_self,    sched_getcpu
global FreeMem_fn
extern malloc, realloc, free
extern sprintf

section .data align=16
X_ctr: dq 0
data_master_ptr: dq 0
initial_dynamic_length: dq 0
XMM_Stack: dq 0, 0, 0, 0, 0, 0, 0
ThreadID: dq 0
X_ptr: dq 0
X_length: dq 0
X: dq 0
collect_ptr: dq 0
collect_length: dq 0
collect_ctr: dq 0
even_squares_list_ptrs: dq 0, 0, 0, 0
even_squares_list_ctr: dq 0
even_squares_list_length: dq 0
Number_Of_Cores: dq 4
pthread_attr_t: dq 0
pthread_arg: dq 0
Join_Ret_Val: dq 0
tcounter: dq 0
sched_getcpu_array: times 4 dq 0
ThreadIDLocked: dq 0
spin_lock_core: times 4 dq 0
extra_test_array: times 4 dq 0
spin_lock_iter: times 4 dq 0
spin_lock_base_addr: dq 0

; __________

section .text

Init_Cores_fn:

%include "/opt/P01_SH/_Include_Utilities/Buffer_Pointer_Arrays.asm"

mov rax,[Number_Of_Cores]
mov rbx,8
mul rbx
mov [Number_Of_Cores],rax

; _____
; Create Threads

label_0:

; THREAD 1 WORKS IN THIS SECTION TO CREATE THREADS

mov rdi,ThreadID            ; ThreadCount
mov rsi,pthread_attr_t  ; Thread Attributes
mov rdx,Test_fn         ; Function Pointer
mov rcx,pthread_arg
call pthread_create wrt ..plt

mov rdi,[ThreadID]      ; id to wait on
mov rsi,Join_Ret_Val        ; return value
call pthread_join wrt ..plt

mov rax,[tcounter]
add rax,8
mov [tcounter],rax
mov rbx,[Number_Of_Cores]
cmp rax,rbx
jl label_0

; _____

jmp label_900 ; All threads return here, and exit

; ______________________________________

Test_fn:

; Get the core number
call sched_getcpu wrt ..plt
mov rbx,8 ; multiply by 8
mul rbx
push rax

pop rax
mov rbx,rax
push rax

Next_Stop: ; THIS IS WHERE EACH THREAD STOPS
mov rdi,extra_test_array
mov [rdi+rbx],rbx
jmp label_899 ; ******************

;__________

label_899:

pop rax

ret

; __________

label_900:

%include "/opt/P01_SH/_Include_Utilities/Sys_Close_Include.asm"

mov rdi,extra_test_array
mov rax,rdi

ret

;__________
;Free the memory

FreeMem_fn:

;The pointer is passed back in rcx (of course)

sub rsp,40
call free wrt ..plt
add rsp,40
ret

; __________
; Main Entry


Main_Entry_fn:
push rdi
push rbp
push rbx
push r15
xor r15,r15
push r14
xor r14,r14
push r13
xor r13,r13
push r12
xor r12,r12
push r11
xor r11,r11
push r10
xor r10,r10
push r9
xor r9,r9
push r8
xor r8,r8
movsd [XMM_Stack+0],xmm13
movsd [XMM_Stack+8],xmm12
movsd [XMM_Stack+16],xmm11
movsd [XMM_Stack+24],xmm15
movsd [XMM_Stack+32],xmm14
movsd [XMM_Stack+40],xmm10
mov [X_ptr],rdi
mov [data_master_ptr],rsi
; Now assign lengths
lea rdi,[data_master_ptr]
mov rbp,[rdi]
xor rcx,rcx
movsd xmm0,qword[rbp+rcx]
cvttsd2si rax,xmm0
mov [X_length],rax
add rcx,8

; __________
; Write variables to assigned registers

mov r15,0
lea rdi,[rel collect_ptr]
mov r14,qword[rdi]
mov r13,[collect_ctr]
mov r12,[collect_length]
lea rdi,[rel X_ptr]
mov r11,qword[rdi]
mov r10,[X_length]

; __________

call Init_Cores_fn

movsd xmm10,[XMM_Stack+0]
movsd xmm14,[XMM_Stack+8]
movsd xmm15,[XMM_Stack+16]
movsd xmm11,[XMM_Stack+24]
movsd xmm12,[XMM_Stack+32]
movsd xmm13,[XMM_Stack+40]
pop r8
pop r9
pop r10
pop r11
pop r12
pop r13
pop r14
pop r15
pop rbx
pop rbp
pop rdi
ret
;__________

NASM代码是一个长清单,但重点放在label_0 (创建线程的地方)和Test_fn (新线程到达的第一个断点)上。

对于gdb调度程序锁定的问题,我非常感谢任何输入。谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-01-06 20:37:39

您的程序集程序似乎是这样做的:

代码语言:javascript
复制
pthread_create(&ThreadID, ..., Test_fn, ...);
pthread_join(ThreadID, ...);

首先,这实际上并没有给您任何并行性,因为您创建并立即等待您刚刚创建的线程。您也可以轻松地直接调用Test_fn(),并且开销更小。

其次,如果停止新创建的线程(就像使用调度程序锁定一样),那么主线程将阻塞等待加入新创建的线程,并且它将永远阻塞。所以你的程序当然会陷入僵局。

更新:

,我认为我需要在pthread_create之后调用pthread_join,这样所有线程都会在主线程退出之前完成。

这是正确的。但他们的做法通常是这样的:

代码语言:javascript
复制
const int NThreads = ...;
pthread_t tids[NThreads];

for (int j = 0; j < NThreads; j++)
  pthread_create(&tids[j], ...);

// All threads have started, and are now running in parallel with the main thread.
// Wait for them to finish.
for (int j = 0; j < NThreads; j++)
  pthread_join(tids[j], ...);

// All done.
return 0;
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59618107

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档