我遇到一个问题,即在clone()系统调用之后某个时候realloc()死锁。
我的代码是:
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <linux/types.h>
#define CHILD_STACK_SIZE 4096*4
#define gettid() syscall(SYS_gettid)
#define log(str) fprintf(stderr, "[pid:%d tid:%d] "str, getpid(),gettid())
int clone_func(void *arg){
int *ptr=(int*)malloc(10);
int i;
for (i=1; i<200000; i++)
ptr = realloc(ptr, sizeof(int)*i);
free(ptr);
return 0;
}
int main(){
int flags = 0;
flags = CLONE_VM;
log("Program started.\n");
int *ptr=NULL;
ptr = malloc(16);
void *child_stack_start = malloc(CHILD_STACK_SIZE);
int ret = clone(clone_func, child_stack_start +CHILD_STACK_SIZE, flags, NULL, NULL, NULL, NULL);
int i;
for (i=1; i<200000; i++)
ptr = realloc(ptr, sizeof(int)*i);
free(ptr);
return 0;
}
gdb中的callstack是:
[pid:13268 tid:13268] Program started.
^Z[New LWP 13269]
Program received signal SIGTSTP, Stopped (user).
0x000000000040ba0e in __lll_lock_wait_private ()
(gdb) bt
#0 0x000000000040ba0e in __lll_lock_wait_private ()
#1 0x0000000000408630 in _L_lock_11249 ()
#2 0x000000000040797f in realloc ()
#3 0x0000000000400515 in main () at test-realloc.c:36
(gdb) i thr
2 LWP 13269 0x000000000040ba0e in __lll_lock_wait_private ()
* 1 LWP 13268 0x000000000040ba0e in __lll_lock_wait_private ()
(gdb) thr 2
[Switching to thread 2 (LWP 13269)]#0 0x000000000040ba0e in __lll_lock_wait_private ()
(gdb) bt
#0 0x000000000040ba0e in __lll_lock_wait_private ()
#1 0x0000000000408630 in _L_lock_11249 ()
#2 0x000000000040797f in realloc ()
#3 0x0000000000400413 in clone_func (arg=0x7fffffffe53c) at test-realloc.c:20
#4 0x000000000040b889 in clone ()
#5 0x0000000000000000 in ?? ()
我的操作系统是debian linux-2.6.32-5-amd64,GNU C Library(Debian EGLIBC 2.11.3-4)稳定版本2.11.3。我深深怀疑eglibc是这个bug的罪魁祸首。 在clone()系统调用上,使用realloc()之前还不够吗?
答案 0 :(得分:3)
您不能自己clone
使用CLONE_VM
- 或者如果您这样做,您必须至少确保在调用clone
后限制自己调用标准库中的任何函数无论是父母还是孩子。为了让多个线程或进程共享相同的内存,访问共享资源(如堆)的任何函数的实现都需要
clone
自己创建的新“线程”以获得正确设置的线程指针。正确的解决方案是使用pthread_create
,而不是clone
。
答案 1 :(得分:0)
你不能这样做:
for (i=0; i<200000; i++)
ptr = realloc(ptr, sizeof(int)*i);
free(ptr);
第一次循环,i
为零。 realloc( ptr, 0 )
相当于free( ptr )
,您不能free
两次。
答案 2 :(得分:0)
我在clone()系统调用中添加了一个标志CLONE_SETTLS。然后僵局消失了。 所以我认为eglibc的realloc()使用了一些TLS数据。当新线程在没有新TLS的情况下创建时,一些锁(在TLS中)在这个线程和他父亲之间共享,而realloc()使用那些锁定。因此,如果有人想直接使用clone(),最好的方法是为新线程分配一个新的TLS。
代码段喜欢这个:
flags = CLONE_VM | CLONE_SETTLS;
struct user_desc* p_tls_desc = malloc(sizeof(struct user_desc));
clone(clone_func, child_stack_start +CHILD_STACK_SIZE, flags, NULL, NULL, p_tls_desc, NULL);