进/线/协程--引自阿秀的学习笔记

阿秀的学习笔记:https://interviewguide.cn/

进程、线程与协程区别

1、进程是资源分配的基本单位,运行一个可执行程序会创建一个或多个进程,进程就是运行起来的可执行程序

2、线程是资源调度的基本单位,也是程序执行的基本单位,是轻量级的进程。每个进程中都有唯一的主线程,且只能有一个,主线程和进程是相互依存的关系,主线程结束进程也会结束。

3、线程共享  堆、全局变量、静态变量、指针,引用、文件等,而独自占有栈

一个进程可以创建多少线程,和什么有关?

  • 如果是32 位系统,用户态的虚拟空间只有 3G(3072M),如果创建线程时分配的栈空间是 10M,那么一个进程最多只能创建 300 个左右的线程。
  • 如果是64 位系统,用户态的虚拟空间大到有 128T,理论上不会受虚拟内存大小的限制,而会受系统的参数或性能限制

过多的线程将会导致大量的时间浪费在线程切换上,给程序运行效率带来负面影响,无用线程要及时销毁

外中断和异常有什么区别?

  外中断是指由 CPU 执行指令以外的事件引起,如 I/O 完成中断,表示设备输入/输出处理已经完成,处理器能够发送下一个输入/输出请求。此外还有时钟中断、控制台中断等。

  异常是由 CPU 执行指令的内部事件引起,如非法操作码、地址越界、算术溢出等

进程线程模型

  用户态多线程模型:同一个进程内部有多个线程,所有的线程共享同一个进程的内存空间,进程定义的全局变量会被所有的线程共享

  进程中的所有线程都可以读取和修改全局变量,但线程被 CPU 调用的顺序随机,因此对临界资源的访问要注意安全性

  全局变量的更改不是原子操作,涉及 内存取数、 计算、 写入内存,线程切换可能发生在环节之间。

  线程优势:看似同步执行多个任务,例如:QQ聊天可以一边聊天一天上传文件。

  🔴 线程之间有无先后访问顺序(线程依赖关系)

  🔴 多个线程共享访问同一变量(同步互斥问题)

  线程特有的部分:标识线程的 tid  独立的栈空间

  线程调度只需要保存 线程栈、寄存器数据、程序计数器,切换开销小。

分时系统:

  使一台计算机采用 时间片轮转 的方式同时为多个用户服务的操作系统。可以有效增加资源的使用率。

线程的创建和结束: 

  在一个文件内多个函数通常都是按照 Main 函数中的出现顺序执行,但是在分时系统下,可以让每个函数都作为一个 逻辑流 并发执行,最简单采用 多线程策略。

  在 Main 函数中调用多线程接口创建线程,每个线程对应特定的函数(操作),这样就可以不按照函数出现的顺序来执行,避免了忙等的情况。(线程的随机性)。   

创建线程:int pthread_create(pthread_t *tid,  const pthread_attr_t *attr,   void *(start_rtn)(void),  void *arg);

  创建一个线程,pthread 和 start_routine 不可或缺,分别用于识别线程 和 执行体入口,  其他可以 NULL

  🔴 pthread:返回线程的 tid, *pthread 值 即为 tid, 类型 pthread_t == unsigned long int 

  🔴 attr:指向线程属性结构体的指针,用于改变创建线程的属性,NULL表示使用默认值

  🔴 start_routine:线程执行函数的首地址,传入函数指针。

  🔴 arg:通过地址传递来传递函数参数,是无符号类型指针(void *),可以传任意类型变量的地址,在被传入函数中先强制类型转换成所需类型即可。

获取线程ID: pthread_t pthread_self();

  调用时,打印线程ID

等待线程结束:int pthread_join(pthread_t itd, void ** retval);

  主线程调用,等待子线程退出并回收其资源,类似进程中 wait / waitpid  回收僵尸进程, 调用 pthread_join 的线程会被阻塞。

  🔴 tid:创建线程时通过指针得到的 tid (线程号)

  🔴 retval:指向返回值的指针。

线程结束: pthread_exit(void * retval);

  子线程执行,用来结束当前线程并通过 retval 传递返回值,该返回值可以通过 pthread_join 获得。

  retval:指向返回值的指针。

分离线程: int pthread_detach(pthread_t tid);

  主线程、子线程均可调用。主线程中   pthread_detach(tid), 子线程中 pthread_detach(pthread_self()),调用后和主线程分离,子线程结束时立即回收资源

  tid:线程号

多进程:每一个进程是资源分配的基本单位

  进程结构:代码段、堆栈段、数据段。代码段是静态的二进制代码,多个程序可以共享。

  父进程创建子进程之后,父、子进程除了 pid 外,几乎所有的部分几乎一样。

  父子进程共享全部数据,但并不是对同一块数据进行操作,子进程在读写数据时会通过   写时复制机制   将公共的数据拷贝,在拷贝数据上操作。

  子进程要运行自己的代码段,可以通过调用 execv()函数重新加载新的代码段,之后与父进程独立开。

  在shell中执行程序 就是通过 shell 进程 先 fork() 一个子进程,再通过 execv() 重新加载新的代码段的过程。

进程的创建与结束:

  进程有两种创建方式,一种是 操作系统创建的, 另一种是父进程创建的。

  从计算机启动到终端执行程序的过程为:  0号进程 -> 1号内核进程 -> 1号用户进程(init进程) -> getty进程 -> shell进程 -> 命令行执行进程。

  所以在命令行中通过 ./program 执行可执行文件时候,所有创建的进程都是 shell 进程的子进程,这也就是为什么 shell 已关闭, 在 shell 执行的进程都自动被关闭的原因。

  从 shell进程 到创建其他子进程需要通过以下接口:

创建进程:pid_t fork(void);

  返回值:出错 返回 -1;  父进程中返回 pid > 0;  子进程 pid == 0

结束进程:void exit(int status);

  status是退出状态,保存在全局变量中,通常0表示正常退出。

获得 PID:pid_t getpid(void);

  返回调用者的 pid

获得父进程PID:pid_t getppid(void);

  返回父进程 pid

_exit()  return 和 exit() 区别:

  🔴 exit()是对_exit() 的封装,都会终止进程并做相关收尾工作,最主要的区别是 _exit()函数关闭全部描述符和清理函数后不会刷新流,但exit()会在调用 _exit()函数前刷新数据流。  

  🔴 exit()是函数,但有参数,执行完之后控制权交给系统;

  🔴 return 若在调用函数中,执行完之后控制权交给调用进程,若在 Main函数中,控制权交给系统。

Linux进程控制:

  • 进程地址空间(虚拟地址空间)

    虚拟地址空间为每个进程提供了独占系统地址空间的假象。

    尽管每个进程地址空间内容不尽相同,但是他们的都有相似的结构。X86 Linux进程的地址空间底部是保留给用户程序的,包括文本、数据、堆、栈等,其中文本区和数据区是通过存储器映射方式将磁盘中可执行文件的相应段映射至虚拟地址空间中。

  • 对于32位进程来说:代码段从0x08048000开始。从0xC0000000开始到0xFFFFFFFF是内核地址空间通常情况下代码运行在用户态(使用0x00000000 ~ 0xC00000000的用户地址空间),当发生系统调用、进程切换等操作时CPU控制寄存器设置模式位,进入内核模式,在该状态(超级用户模式)下进程可以访问全部存储器位置和执行全部指令。

    也就说32位进程的地址空间都是4G,但用户态下只能访问低3G的地址空间,若要访问3G ~ 4G的地址空间则只有进入内核态才行

  • 进程控制块(PCB)

    进程的调度实际就是内核选择相应的进程控制块,被选择的进程控制块中包含了一个进程基本的信息

  • 上下文切换

    内核管理所有进程控制块,而进程控制块记录了进程全部状态信息。每一次进程调度就是一次上下文切换所谓的上下文本质上就是当前运行状态,主要包括通用寄存器、浮点寄存器、状态寄存器、程序计数器、用户栈和内核数据结构(页表、进程表、文件表)等。

    进程执行时刻,内核可以决定抢占当前进程并开始新的进程,这个过程由内核调度器完成,当调度器选择了某个进程时称为该进程被调度,该过程通过上下文切换来改变当前状态。

    一次完整的上下文切换通常是进程原先运行于用户态,之后因系统调用或时间片到切换到内核态执行内核指令,完成上下文切换后回到用户态,此时已经切换到进程B。

posted on   廿陆  阅读(89)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示