• linker
    2021-11-03
    思考题:线程的用户栈是pthread函数提前创建的吗?

    作者回复: 回答正确!写时复制只能发生在进程之间。同一个进程的线程因为共享资源,只能提前分配。

    
    11
  • pedro
    2021-11-03
    fork 系统调用,只会新建一个子进程调用栈,并向其拷贝父进程调用栈数据,所以父子进程保存了同样的寄存器数据,因此造成了 fork 调用一次,而返回两次的现象。 由于 fork 本质会将父进程拷贝一份,作为子进程,这样就会有大量的拷贝工作,fork 会很慢,同时子进程可能不需要这么多的资源,会造成资源浪费,因此主流操作系统,比如 linux 都实现 COW 机制,即写时复制,fork 时对栈以外的资源都先映射到地址空间中,文件、socket 等句柄资源引用计数+1,待子进程访问这些地址时会触发缺页中断,此时内核再来为其分配真正的物理页,这样就节省了时间和空间。

    作者回复: 赞!很准确了。我们在第10节课会讲页中断,那时候就会更加深一层理解。

    
    9
  • 鵼
    2021-11-03
    补充一下:关于coroutine,在优化O1下,因为没有基地址的入栈出栈操作,所以 代码只用删除coroutine下的基地值入栈操作:stack_pointer -= 1; *stack_pointer = (long) base; 就可以了

    作者回复: Good

    共 3 条评论
    8
  • 姑射仙人
    2021-11-13
    进程有两种栈,用户态栈和内核态栈。之前以为一直有一个内核进程在运行,发起系统调用相当于用户进程和内核进程在通信。是不是可以这样理解,进程执行的代码是包含内核代码和用户代码,当执行内核代码时需要进入内核态,当执行用户代码时在用户态。所以各进程的虚拟内存中就包含两部分,内核空间和用户空间,分别存放内核代码和用户代码。感觉理解的很零碎,老师帮看看哪块理解的不对。

    作者回复: 你后面的理解在linux上大致是对的。虽然确实每个进程有自己的内核态栈,但你要牢记,在内核态运行时,内核代码段有能力访问任何一个进程的核心结构。这是用户态和内核态最大的不同。还有,你前边的理解也没错,微内核的操作系统就是这么设计的。windows和minix都是由内核进程提供服务。

    
    4
  • 陈狄
    2021-11-23
    mov %rdi,-0x8(%rbp) mov %rsi,-0x10(%rbp) mov -0x10(%rbp),%rax mov (%rax),%rax mov -0x8(%rbp),%rdx mov %rsp,(%rdx) 请问老师,这段汇编,明明rdi和rsi可以直接拿来用,为什么要先存到栈里面,然后再从栈里面取出来访问,要绕一道?

    作者回复: 编译器的优化没做好,开O1优化就不会了

    
    3
  • Geek_27eb54
    2021-11-14
    海纳,老师,根据之前学的物理地址和虚拟地址,共享内存实际上可不可以理解成虚拟地址到物理地址的转换规则是一致的,私有地址中转换规则不一致?那么在一个进程中的多个线程中的私有内存,会不会有相同的地址呢?或者说我这样理解有问题呢?希望老师可以解答一下

    作者回复: 不是规则不一致哦。规则是永远都一样的,都是MMU根据页表进行三级映射,从虚拟地址映射为物理地址。不一样的是页表里面的内容。两个进程可以把自己的虚拟地址映射到相同的物理地址。这就是共享内存。一个进程里的多个线程共享同一个页表,所以线程的私有内存是肯定不会有相同的地址的。

    
    3
  • 流浪地球
    2021-11-08
    用户态的协程栈是分配在堆空间的吗?看代码是使用了malloc函数。协程的stackful和非stackful是什么却区别呢?

    作者回复: 是的,我们是把堆上的一块内存区域当成了栈来用。这个例子也说明了,内存区域划分是我们根据人的理解去做的划分,而不是说就此固定了的。你可以了解一下js或者python中的generator,他们是stackless的,我们这节课的协程是stackful的。对比一下自己就清楚了。

    
    2
  • 鵼
    2021-11-03
    对于学java的我看懂这段c++代码真不容易啊,好歹看懂了 。最难懂的应该是 协程a了,一开始一直觉得参数NULL,那个stack_pointer就是个null,后来查查资料,指针变量在声明的时候已经分配内存地址了,所以a的stack_pointer就是内存中的一块地址,只是它指向 的是NULL,本身还是一个内存地址。它的作用其实就是为了保存mian函数的rsp,所以才不用赋值(或者说给指定的地址)。 关于思考题:我觉得应该类似于进程那种按需写时复制。原因我认为的比较浅显,也比较尴尬,因为fork和pthread_create都是调用的clone(😅😅),其次线程的资源都是 共享的父亲 ,页表、虚拟地址 、文件描述符啥的应该都是同一个。不对 ,pthread_create的时候是有 参数的,fork没有。那应该是类似协程那种提前创建好的方式,用于保存参数数据。

    作者回复: 哈哈哈,说得很有趣也很正确

    共 2 条评论
    2
  • 张贺
    2021-11-03
    每个线程都可以分配一个内核栈吗?

    作者回复: Linux系统是这样的。这是因为Linux系统没有很好地支持线程,而是直接利用了进程的结构。当然,Linux的多线程支持也在不断地完善中,未来会是怎么样,我们拭目以待。

    
    1
  • 张贺
    2021-11-03
    用户态内核态切换的时候,线程切换了吗?

    作者回复: 没有。当前线程的用户态的状态还会保存在内核态栈上。

    
    1