返回

计算机各类神奇的小问题大全

作为一个很多奇怪问题&bug体质的人,此处用于记录平时的奇思妙想

作为一个很多奇怪问题&bug体质的人,此处用于记录平时的奇思妙想。

https://zhuanlan.zhihu.com/p/83454344

编译与链接相关

windows动态连接库dll居然是用lib导入符号信息(windows专门的编译器)(此时的lib不表示静态连接库),还是linux香啊。。

【手把手教你编写 年轻人的第一个动态链接库-哔哩哔哩】 https://b23.tv/6pddFSv

Q:编译器前后端之区别是不是只在中间代码翻译的职责部分?

比如clang负责转换成机器无关的中间代码。然后llvm后端把它可以转换成机器相关汇编代码

A:

操作系统相关

https://yajin.org/os2018fall/

https://yajin.org/os2018fall/02_os_structures.pdf

Q:用户线程为什么不能独立于内核线程存在?至少要有一个内核线程“与他关联”?

A:

群友的看法:

我的理解是,如果在微内核, 比如fs模块在user层, 用户程序只需要调用fs模块, 那用户程序逻辑上是没有调用内核task, 但是物理上微内核fs模块肯定会调用微内核内核层的vm的task的, 所以用户线程不能独立存在。如果用户程序和操作系统在一个物理机中, 如果用户程序和操作系统要独立, 首先资源要独立, 内存可以协商独立, 比如0x00000a-0x0000fff是操作系统的, 然后0x0001ffff0-0xffffffff是用户程序的. cpu0是给操作系统的, cpu1是给用户程序的. 然后通信用网络, eth0是操作系统的, eth1是用户程序的. 这样的话应该能设计出用户线程是独立的。

我的看法:

(不同操作系统实现不同,这里只针对比较现代的linux。)

首先要注意这东西由于不同操作系统和不同年代的教材众说纷纭,很容易出现概念混淆和理解错误,这里我们以最新的linux手册为准。

在讨论这个问题之前首先要明确几个概念(什么是线程、什么是用户线程。),我们看到有很多地方说到多对一模型,其实这里的用户线程更应该叫协程(你看到很多地方会说这东西不需要syscall就可以创建,process内负责执行流切换无需os)。而我们常说的用户态创建的线程就是一对一模型(pthreads手册中明确提到Both of these are so-called 1:1 implementations, meaning that each thread maps to a kernel scheduling entity),本身需要和内核线程挂钩(创建过程需要syscall和内核线程绑定),而进程本身的主线程必定是和内核线程挂钩;另外在linux中我们用task去称呼会更加合适,linux系统层面没必要分进程线程只需要task就好。只有在我们执行的程序里有需求开pthread 这里才要强调,它会将对应的函数入口给内核线程以便切换。

需要注意的是,在xv6,内核初始化完了切换init后就进入了用户态,此后fork、exec的都是子task,但是需要调度流切换得需要和cpu联系,这就需要内核task才能够运作。(其实这里的子task本身就是可以被调度到的,因为就是PCB)

回答这个问题的关键是理解所谓的线程是怎么拿到cpu资源的,拿到资源意味着被调度器调度。(为什么不讨论进程?因为实际上进程只是一些共享内存的task,而且在linux中PCB就是task_struct)。首先之所以是线程而不是函数是因为他能作为调度单元(可以被调度器切换上下文),在任务调度器(比如pa中的schedule)的眼里,只有task才是调度单元,即处理器上运行的每个任务都是调度器给分配的执行流,只要成为执行流就能够独立上处理器运行了,而内核task可以被内核直接调度,他可以直接做到操作页表,维护cache, 读写系统寄存器等操作。如果用户task(比如协程)不需要内核线程管理,容易出现一些意外现象(虽然还是可以让系统发指令杀死)。这里概念最坑的就是可能混淆协程和在用户态用pthread api 创建的线程以及LWP轻量化进程,实际上前者可以通过是否syscall是否需要和内核互动来区分;而LWP轻量化进程在linux中有时是内核线程的另一种称呼。

为什么说linux中用户态可以/需要绑定一个内核线程?具体看syscall,我们创建线程的过程会调用clone然后和一个内核线程“绑定”(大概是把上下文存储到内核线程task块中这样可以被os看到和调度。)用户task实际上用的是内核task的pcb块,需要一些高级权限的时候就保存上下文内陷然后在内核中处理即可。

如果想要最单纯的用户线程也有执行的权限,关键是你能够怎么切换他的执行流,此时应该只有协程能满足这个需求了,否则要提权的话就是内核线程了,因为能被内核直接schedule。所以严格来说独立的用户线程是不存在的,就算是协程也需要进程调度,而进程的cpu资源源于对应内核task的被调度。

(有趣的是,linux2.6才完全支持了我们现在意义上的用户态线程,linux2.6是2003年的内核版本,由此可见计算机确实是一门很新的学科:) )

reference:

浙大课件Light-Weight Processes: Dissecting Linux Threads:https://yajin.org/os2018fall/04_thread_b.pdf

深入理解Linux内核之内核线程(上):https://zhuanlan.zhihu.com/p/364898425

关于“内核线程”、“用户线程”概念的理解:https://blog.csdn.net/u012927281/article/details/51602898

图解进程、线程:https://blog.csdn.net/fuzhongmin05/article/details/119448800

Light-Weight Processes: Dissecting Linux Threads:https://www.opensourceforu.com/2011/08/light-weight-processes-dissecting-linux-threads/

What are Linux Processes, Threads, Light Weight Processes, and Process State:https://www.thegeekstuff.com/2013/11/linux-process-and-threads/

man pthreads:https://man7.org/linux/man-pages/man7/pthreads.7.html

Q:linux线程的生命周期是怎么样的?怎么被创建和销毁?内核task能不能被复用?

A: 这个说的比较清楚:https://xieyu.github.io/blog/pthread/glibc-pthread-implement-thread-life-cycle.html

  • 如果 pthread_join 发生在结束后不久,资源还未被回收,函数会立即返回。

  • 如果 pthread_join 发生在结束以后一段时间,可能会得到 ESRCH (no such thread) 错误。

  • 如果 pthread_join 发生在之后很久很久很久很久,资源被释放又被再次复用 (pthread_t 是一个的确可能被复用的整数),我不就 join 了另一个线程了吗?这恐怕要出大问题。

  • 特别的:(其他情况exit后都会被资源回收)

没有task复用的说法。

reference:

jyy:http://jyywiki.cn/OS/2022/labs/M2

网络相关

python相关

Q:为什么开了multiprocessing的pool再开process就不会出现信息?

A:不知道,但你记住要多次fork只能一直process就对了。

Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack designed by Jimmy