【问题标题】:Linux sys_clone. Free'ing stack memoryLinux 系统克隆。释放堆栈内存
【发布时间】:2016-08-05 11:58:27
【问题描述】:

我正在尝试使用clone() 系统调用来实现pthread_create 的版本。我很好奇线程退出后pthread free 的堆栈内存如何。这是我尝试过的:

struct ThreadInfo{...}

void ThreadPrint(){...}

void HandleThread(args){
ThreadInfo* info = (cast here)args;

info->callfunction;

free(info->stack)
}


void CreateThread(callfunction){

ThreadInfo info = {};
info.stack = //alloc stack
info.callfunction = callfunction;

clone(HandleThread,...,&info)

}

int main(){
CreateThread(ThreadPrint);
}

此方法不起作用,因为进程在HandleThread 中的free() 函数调用期间仍需要使用其堆栈。这可能是因为当堆栈被释放并且 free 不能再返回时,返回地址丢失了,所以也许使用原始系统调用可能会起作用。除此之外,我不确定如何在不使用单独进程的情况下释放线程堆栈。

编辑:对于那些感兴趣的人,这是我为让线程释放自己的堆栈而进行的系统调用。

 __asm__ volatile (
            "mov $11,%%rax\n"  //call munmap
             "mov %[addr],%%rdi\n"
             "mov %[len],%%rsi\n"
             "syscall\n"
            "xor %%rdi,%%rdi\n"
            "mov $60,%%rax\n"//manually call exit
             "syscall\n":: [addr] "g" (info->stack), [len] "g" (info->stacksize)
             );

据我所知,您必须使用内联汇编。使用 C 函数包装器将使线程无处可返回。如果有人有更好的解决方案,我很想听听。更好的是,如果有人知道 pthread 库的内部结构,很想听听。谢谢。

【问题讨论】:

    标签: c linux multithreading clone


    【解决方案1】:

    您不会释放刚刚创建的线程中的堆栈。父进程,即你的主线程拥有堆栈,当线程返回时它会释放它。

    手册页有一个使用克隆的示例,包括正确创建堆栈。

    http://linux.die.net/man/2/clone

    您需要设置一个数据结构来跟踪线程及其堆栈,以便在您测试孩子是否还活着或收到它已死的信号时进行清理。

    【讨论】:

    • 嗯....我刚刚对 munmap 进行了原始系统调用,它解决了我的问题。就像我想的那样,对 munmap 的 C 调用无法访问已释放堆栈上的返回地址。使用原始系统调用不需要返回地址。使用单独的数据结构有什么好处?如果是这种情况,我不需要一个单独的进程来管理死线程吗?
    • 是的。您通常会管理来自父级的线程。这意味着父母需要使用从克隆调用中获得的pid 来跟踪它们。看看这家伙在这里做了什么...github.com/adamhooper/code-from-adamhoopers-school-days/blob/…
    • 感谢您的链接。当我有时间时,我会更深入地研究它。但是,这不意味着用户必须自己显式删除线程吗?这没什么错,但如果我没记错的话,pthreads 中不是这样,不是吗?
    • 看看 pthread_exit 和 pthread_join 看看他们在做什么。请记住,您是编写类似 pthread 库的人,您的用户可能不需要 free 任何东西,但这并不意味着您不必将其作为 API 的一部分。
    • 是的,前几天刚下载了pthreads的源码。需要一段时间,它是巨大的。只是根据我对 pthreads 的理解,用户不必显式调用 pthread_exit ,即使他们这样做,它也是实际调用函数的线程,假设函数句柄已清理。 pthread_join 只处理僵尸进程,因此据我所知,它与堆栈清理并不真正相关。是的,我的实现确实在退出时通过显式调用系统调用来自动释放其内存,而不是使用不起作用的 C 函数包装器。
    【解决方案2】:

    管理线程堆栈由 glibc 库完成,使用mmap 分配线程堆栈,munmap 释放它们。

    回想一下,线程可以是可连接的或可分离的。

    对于可连接线程,释放其所有资源可以推迟到调用pthread_join。线程库可以在那时释放其堆栈(或将其标记为空闲以供重复使用)。

    当一个分离的线程终止时,即使库没有收到通知,它最终也会寻找未使用的堆栈并回收它。

    【讨论】:

    • 让我知道准确引用 Glibc 源代码树是否有帮助。
    猜你喜欢
    • 1970-01-01
    • 2016-07-25
    • 2018-08-12
    • 2016-12-20
    • 1970-01-01
    • 1970-01-01
    • 2011-11-15
    • 1970-01-01
    • 2012-09-17
    相关资源
    最近更新 更多