【问题标题】:How to avoid a memory leak by using pthread_cancel?如何使用 pthread_cancel 避免内存泄漏?
【发布时间】:2014-07-25 09:44:56
【问题描述】:

我有一个程序应该启动一个线程。为了避免退出软件,线程在无限循环中运行,我加入了线程。这个线程永远不应该返回一个值。所以现在我有一个问题,在我调用 pthread_cancel valgrind 后检测到内存泄漏。如何避免这种内存泄漏?

Valgrind 输出:

==5673== 136 bytes in 1 blocks are possibly lost in loss record 4 of 8
==5673==    at 0x4026A68: calloc (vg_replace_malloc.c:566)
==5673==    by 0x40111FB: _dl_allocate_tls (dl-tls.c:300)
==5673==    by 0x404E5A0: pthread_create@@GLIBC_2.1 (allocatestack.c:580)
==5673==    by 0x804C44E: start (mythread.c:25)
==5673==    by 0x804D128: main (main.c:10)

代码:

int main(){
    signal(SIGINT,cleanup);
    signal(SIGQUIT,cleanup);
    signal(SIGSEGV,cleanup);
    start();
    return 0;
}

int start()
{
    pthread_create(&thread_id[0],NULL,&threadhandler,NULL);
    pthread_join(thread_id[0],NULL);
    return err;
}

void cleanup(){
   pthread_cancel(thread_id[0]);
   exit(0);
}

void cleanup_tcp(void *p){
}


void* threadhandler(void *arg)
{
    (void) arg;
    int status = 0;
    while(TRUE){
        pthread_cleanup_push(cleanup_tcp,NULL);
        pthread_testcancel();
        fprintf(stderr,"Run\n");
        pthread_cleanup_pop(0);
    }
    return NULL;
}

【问题讨论】:

  • 在取消之前分离线程(通过调用pthread_detach())可能会有所帮助(有点)。

标签: c memory-leaks pthreads pthread-join


【解决方案1】:

您已经正确识别出使用pthread_cancel() 的一个缺点:线程清理例程未释放/释放的任何资源随后都会泄漏。在您的情况下,似乎线程库本身可能分配了一些未释放的内存。

IMO 更好的方法是创建一种机制来通知threadhandler 线程它应该终止。例如

static volatile sig_atomic_t done = 0;
...
void cleanup()
{
    done = 1;
}

void* threadhandler(void* arg)
{
    while (!done)
        fprintf(stderr, "Run\n");
    return NULL;
}

【讨论】:

  • volatile 是多余的和有害的。使用原子变量就足够了。
  • @cmaster 我不同意。 X/Open 规范明确引用了volatile 限定符:“如果信号的出现不是由于调用 abort()、raise()、[CX] [Option Start] kill()、pthread_kill() 或 sigqueue (), [Option End] 如果信号处理程序引用具有静态存储持续时间的任何对象,而不是通过将值分配给声明为 volatile sig_atomic_t, ..."的对象,则行为未定义。此外,“此参考页上描述的功能符合 ISO C 标准”。
  • 好吧,可能我对 X/Open 的了解不够,我根据 C 标准的条款来判断,假设 sig_atomic_t 是相当于 C 标准定义为原子的类型.如果是这样的话,那么volatile 就没有用了。但现在在我看来,X/Open 规范是在 C 标准定义的原子类型之前编写的,所以现在我猜 volatile 确实需要与 sig_atomic_t 结合使用。尽管如此,我还是建议使用当前 C 标准的原子类型。
  • @cmaster 请注意,并非所有平台都有符合 C11 的本机编译器。
猜你喜欢
  • 1970-01-01
  • 2010-12-22
  • 1970-01-01
  • 2020-05-13
  • 1970-01-01
  • 2012-10-22
  • 2020-04-23
相关资源
最近更新 更多