gpt4 book ai didi

c - Malloc 段错误

转载 作者:太空狗 更新时间:2023-10-29 16:42:55 25 4
gpt4 key购买 nike

这是发生段错误的代码片段(未调用错误):

job = malloc(sizeof(task_t));
if(job == NULL)
perror("malloc");

更准确地说,gdb 说 segfault 发生在 __int_malloc 调用中,这是由 malloc 进行的子例程调用.

由于 malloc 函数是与其他线程并行调用的,最初我认为这可能是问题所在。我使用的是 glibc 2.19 版。

数据结构:

typedef struct rv_thread thread_wrapper_t;

typedef struct future
{
pthread_cond_t wait;
pthread_mutex_t mutex;
long completed;
} future_t;

typedef struct task
{
future_t * f;
void * data;
void *
(*fun)(thread_wrapper_t *, void *);
} task_t;

typedef struct
{
queue_t * queue;
} pool_worker_t;

typedef struct
{
task_t * t;
} sfuture_t;

struct rv_thread
{
pool_worker_t * pool;
};

现在未来的实现:

future_t *
create_future()
{
future_t * new_f = malloc(sizeof(future_t));
if(new_f == NULL)
perror("malloc");
new_f->completed = 0;
pthread_mutex_init(&(new_f->mutex), NULL);
pthread_cond_init(&(new_f->wait), NULL);
return new_f;
}

int
wait_future(future_t * f)
{
pthread_mutex_lock(&(f->mutex));
while (!f->completed)
{
pthread_cond_wait(&(f->wait),&(f->mutex));
}
pthread_mutex_unlock(&(f->mutex));
return 0;
}

void
complete(future_t * f)
{
pthread_mutex_lock(&(f->mutex));
f->completed = 1;
pthread_mutex_unlock(&(f->mutex));
pthread_cond_broadcast(&(f->wait));
}

线程池本身:

pool_worker_t *
create_work_pool(int threads)
{
pool_worker_t * new_p = malloc(sizeof(pool_worker_t));
if(new_p == NULL)
perror("malloc");
threads = 1;
new_p->queue = create_queue();
int i;
for (i = 0; i < threads; i++){
thread_wrapper_t * w = malloc(sizeof(thread_wrapper_t));
if(w == NULL)
perror("malloc");
w->pool = new_p;
pthread_t n;
pthread_create(&n, NULL, work, w);
}
return new_p;
}

task_t *
try_get_new_task(thread_wrapper_t * thr)
{
task_t * t = NULL;
try_dequeue(thr->pool->queue, t);
return t;
}

void
submit_job(pool_worker_t * p, task_t * t)
{
enqueue(p->queue, t);
}

void *
work(void * data)
{
thread_wrapper_t * thr = (thread_wrapper_t *) data;
while (1){
task_t * t = NULL;
while ((t = (task_t *) try_get_new_task(thr)) == NULL);
future_t * f = t->f;
(*(t->fun))(thr,t->data);
complete(f);
}
pthread_exit(NULL);
}

最后是 task.c:

pool_worker_t *
create_tpool()
{
return (create_work_pool(8));
}

sfuture_t *
async(pool_worker_t * p, thread_wrapper_t * thr, void *
(*fun)(thread_wrapper_t *, void *), void * data)
{
task_t * job = NULL;
job = malloc(sizeof(task_t));
if(job == NULL)
perror("malloc");
job->data = data;
job->fun = fun;
job->f = create_future();
submit_job(p, job);
sfuture_t * new_t = malloc(sizeof(sfuture_t));
if(new_t == NULL)
perror("malloc");
new_t->t = job;
return (new_t);
}

void
mywait(thread_wrapper_t * thr, sfuture_t * sf)
{
if (sf == NULL)
return;
if (thr != NULL)
{
while (!sf->t->f->completed)
{
task_t * t_n = try_get_new_task(thr);
if (t_n != NULL)
{
future_t * f = t_n->f;
(*(t_n->fun))(thr,t_n->data);
complete(f);
}
}
return;
}
wait_future(sf->t->f);
return ;
}

该队列为lfds无锁队列。

#define enqueue(q,t) {                                 \
if(!lfds611_queue_enqueue(q->lq, t)) \
{ \
lfds611_queue_guaranteed_enqueue(q->lq, t); \
} \
}

#define try_dequeue(q,t) { \
lfds611_queue_dequeue(q->lq, &t); \
}

只要调用异步的次数非常多,就会出现问题。

Valgrind 输出:

Process terminating with default action of signal 11 (SIGSEGV)
==12022== Bad permissions for mapped region at address 0x5AF9FF8
==12022== at 0x4C28737: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)

最佳答案

我已经弄清楚问题出在哪里:堆栈溢出。

首先,让我解释一下为什么堆栈溢出会发生在 malloc 内部(这可能就是您阅读本文的原因)。当我的程序运行时,每次它开始执行(递归地)另一个任务时堆栈大小都会不断增加(因为我的编程方式)。但是对于每次这样的时间,我都必须使用 malloc 分配一个新任务。然而,malloc 进行其他子例程调用,这使得堆栈增加其大小甚至超过执行另一个任务的简单调用。所以,发生的事情是,即使没有 malloc,我也会出现堆栈溢出。但是,因为我有 malloc,所以堆栈溢出的那一刻是在 malloc 中,然后通过另一个递归调用溢出。下面的插图显示了正在发生的事情:

初始堆栈状态:

-------------------------
| recursive call n - 3 |
-------------------------
| recursive call n - 2 |
-------------------------
| recursive call n - 1 |
-------------------------
| garbage |
-------------------------
| garbage | <- If the stack passes this point, the stack overflows.
-------------------------

在 malloc 调用期间堆栈:

-------------------------
| recursive call n - 3 |
-------------------------
| recursive call n - 2 |
-------------------------
| recursive call n - 1 |
-------------------------
| malloc |
-------------------------
| __int_malloc | <- If the stack passes this point, the stack overflows.
-------------------------

然后堆栈再次收缩,我的代码进入了新的递归调用:

-------------------------
| recursive call n - 3 |
-------------------------
| recursive call n - 2 |
-------------------------
| recursive call n - 1 |
-------------------------
| recursive call n |
-------------------------
| garbage | <- If the stack passes this point, the stack overflows.
-------------------------

然后,它在这个新的递归调用中再次调用 malloc。然而,这次它溢出了:

-------------------------
| recursive call n - 3 |
-------------------------
| recursive call n - 2 |
-------------------------
| recursive call n - 1 |
-------------------------
| recursive call n |
-------------------------
| malloc | <- If the stack passes this point, the stack overflows.
-------------------------
| __int_malloc | <- This is when the stack overflow occurs.
-------------------------

[答案的其余部分更侧重于为什么我在我的代码中特别遇到这个问题。]

通常,当递归计算斐波那契数列时,例如,对于某个数字 n,堆栈大小随该数字线性增长。但是,在这种情况下,我正在创建任务,使用队列来存储它们,并使 (fib) 任务出队以供执行。如果你把它画在纸上,你会看到任务的数量随着 n 呈指数增长,而不是线性增长(还要注意,如果我使用堆栈来存储创建任务时,分配的任务数量为以及堆栈大小只会随 n 线性增长。所以发生的事情是堆栈随 n 呈指数增长,导致堆栈溢出......现在是为什么在对 malloc 的调用中发生溢出的部分。所以基本上,作为我在上面解释过,堆栈溢出发生在malloc调用内部,因为它是堆栈最大的地方。发生的事情是堆栈几乎爆炸,并且由于malloc调用其中的函数,堆栈增长不仅仅是调用mywait和小谎。

谢谢大家!如果不是你的帮助,我可能无法弄清楚!

关于c - Malloc 段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22051294/

25 4 0
文章推荐: html - OGG 真的是 HTML5 视频完全兼容所必需的吗?
文章推荐: javascript - 用
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com