- 了解Linux下多线程fork和多进程pthread以及同步机制(信号,信号量,互斥锁),了解RTSP和RTMP协议,H264/H265视频编解码协议。
- 多线程和多进程,同步机制,
- 进程和线程
- 什么是进程
- 进程是资源分配的基本单位,它是程序执行时的一个实例,在程序运行时创建
- Linux中创建线程的方式
- 函数:
- pthread_create函数详解(向线程函数传递参数)
pthread_create函数详解(向线程函数传递参数)_焱齿的博客-优快云博客^v91^insert_down1,239^v12^control&utm_term=pthread_create&spm=1018.2226.3001.4187
- int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
- 参数解释
- thread:指向pthread_t类型的指针,用于存储新创建线程的标识符。新线程的ID将在这里返回。
- attr:指向pthread_attr_t类型的指针,用于指定线程的属性,通常可以设置为NULL,表示使用默认属性。
- start_routine:是一个指向函数的指针,表示新线程将要执行的函数。该函数的返回类型必须为void*,参数类型为void*。即新线程在执行时,会调用start_routine函数,并将arg作为参数传递给它。
- arg:是传递给start_routine函数的参数,可以是任意类型的指针。
- pthread_create函数详解(向线程函数传递参数)
- 例程
- 入下
- 程序中共创建了 2 个线程,分别命名为 myThread1 和 myThread2。myThread1 和 myThread2 线程执行的都是 threadFun() 函数,不同之处在于,myThread1 线程没有给 threadFun() 函数传递任何数据,而 myThread2 线程向 threadFun() 函数传递了 “http://www.biancheng.net” 这个字符串。从程序的执行过程不难看出, pthread_create() 函数成功创建的线程会自动执行指定的函数,不需要手动开启。此外,为了确保创建的线程能在主线程之前执行完,程序中调用 sleep() 函数延缓了主线程的执行速度。您可以尝试将程序中的 sleep() 函数全部注释掉,然后重新编译、执行此程序。整个进程会随着主线程执行结束而立即终止,由于主线程执行太快,子线程可能尚未执行完就被强制终止。
- 原文链接:https://blog.youkuaiyun.com/qq_41854911/article/details/118718848
- 入下
- 函数:
- Linux中创建线程的方式
- 进程是资源分配的基本单位,它是程序执行时的一个实例,在程序运行时创建
- 什么是线程
- 线程是程序执行的最小单位,是进程的一个执行流,一个线程由多个线程组成的。
- 进程和线程的区别
- 1.进程是资源分配的最小单位
- 2.线程是程序执行的最小单位也是处理器调度的基本单位,但进程不是,两者均可并发执行
- 3.进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据,使用相同的地址空间因此,CPU切换一个线程的花费远比进程小很多,同时创建一个线程的开销也比进程小很多。
- 4.线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需4要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也跟着死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
- 5.进程切换时,消耗的资源大,效率低。所以涉及到频繁的切换时,使用线程要好于进程。同样如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程。
- 6.执行过程:每个独立的进程有一个程序运行的入口、顺序执行序列和程序入口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
- 7.线程执行开销小,但是不利于资源的管理和保护。线程适合在SMP机器(双CPU系统)上运行。进程执行开销大,但是能够很好的进行资源管理和保护,可以跨机器迁移
- 什么时候使用多进程,什么时候使用多线程
- 对资源的管理和保护要求高,不限制开销和效率时,使用多进程。
- 要求效率高,频繁切换时,资源的保护管理要求不是很高时,使用多线程。
- 进程有几种状态?画一下进程状态转换图 ?
- 进程可以分为五个状态,分别是:
- 1.创建状态
- 一个应用程序从系统上启动,首先就是进入创建状态,需要获取系统资源创建进程管理块( PCB:Process Control Block ) 完成资源分配
- 2. 就绪状态
- 在创建状态完成之后,进程已经准备好,但是还未获得处理器资源,无法运行
- 3.运行状态
- 获取处理器资源,被系统调度,开始进入运行状态。如果进程的时间片用完了就进入就绪状态.
- 4.阻塞状态
- 在运行状态期间,如果进行了阻塞的操作,如耗时的I/O操作,此时进程暂时无法操作就进入到了阻塞状态,在这些操作完成后就进入就绪状态
- 5.终止状态
- 进程结束或者被系统终止,进入终止状态
- 1.创建状态
- 状态图转化
- 转化图
- 转化图
- 进程可以分为五个状态,分别是:
- 创建进程的几种方式
- 创建进程的多种方式但凡是硬件,都需要有操作系统去管理,只要有操作系统,就有进程的概念,就需要有创建进程的方式,一些操作系统只为个应用程序设计,比如扫地机器人,一旦启动,所有的进程都已经存在。
- 而对于通用系统(跑很多应用程序),需要有系统运行过程中创建或撤销进程的能力,主要分为4种形式创建新的进程:
- 1.系统初始化(查看进程 inux中用ps命令,windows中用任务管理器,前台进程负责与用户交互,后台运行的进程与用户无关,运行在后台并且只在需要时才唤醒的进程,称为守护进程,如电子邮件.web页面、新闻、打印 )
- 2.一个进程在运行过程中开启了子进程(如 nginx开启多进程,os.fork, subprocess Popen等)
- 3.用户的交互式请求,而创建一个新进程(如用户用鼠标双击任意款软件图片:q微信暴风影音等).
- 4.一个批处理作业的初始化(只在大型机的批处理系统中应用)无论哪-种,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的。
- 进程的通信方式,优缺点
- 管道(pipe)
- 管道这种通讯方式有两种限制,一是半双工的通信,数据只能单向流动,二是只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系.
- 流管道s_pipe: 去除了第一种限制,可以双向传输( 全双工)
- 管道可用于具有亲缘关系进程间的通信。命名管道:name_pipe克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信( 命名管道也交FIFO)。
- 信号量(semophore)
- 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
- 消息队列(message queue)
- 消息队列是由消息组成的链表,存放在内核中并由消息队列标识符标识。
- 消息队列是消息的链接表,包括Posix消息队列svstem V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
- 信号(singnal)
- 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。主要作为进程间以及同一进程不同线程之间的同步手段。
- 共享内存(shared memory)
- 共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。
- 套接字(socket)
- 套解字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。
- 优缺点比较:
- 管道
- 速度慢,容量有限,只有父子进程能通讯。
- FIFO
- 任何进程间都能通讯,但速度慢。
- 消息队列
- 容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题,消息队列可以不再局限于父子进程,而允许任意进程通过共享消息队列来实现进程间通信,并由系统调用函数来实现消息发送和接收之间的同步,从而使得用户在使用消息缓冲进行通信时不再需要考虑同步问题,使用方便但是信息的复制需要额外消耗CPU的时间,不适宜于信息量大或操作频繁的场合。此种方法不太常用。
- 信号量
- 不能用来传递复杂消息,只能用来同步
- 共享内存
- 利用内存缓冲区直接交换信息,无须复制,快捷、信息量大是其优点。共享内存块提供了在任意数量的进程之间进行高效双向通信的机制。每个使用者都可以读取写入数据,但是所有程序之间必须达成并遵守一定的协议,以防止诸如在读取信息之前覆写内存空间等竞争状态的出现。
- 进程间通信方式的选择
- PIPE和FIFO(有名管道)用来实现进程间相互发送非常短小的、频率很高的消息,这两种方式通常适用于两个进程间的通信。
- 共享内存用来实现进程间共享的、非常庞大的、读写操作频率很高的数据,这种方法适用于多进程间的通信。
- 其他考虑用socket。主要应用在分布式开发中
- 管道
- 管道(pipe)
- 线程间同步方法有哪些 ?
- 现在流行的进程线程同步互斥的控制机制,其实是由最原始、最基本的4种方法( 临界区、互斥量、信号量和事件)实现的。
- 1.临界区:
- 通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程访问共享资源,如果有多个线程试图访问共享资源,那么当有一个线程进入后,其他试图访问共享资源的线程将会被挂起,并一直等到进入临界区的线程离开,临界在被释放后,其他线程才可以抢占。
- 2.互斥量:
- 为协调对一个共享资源的单独访问而设计,只有拥有互斥量的线程,才有权限去访问系统的公共资源,因为互斥量只有一个,所以能够保证资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享。
- 3.信号量:
- 为控制一个具有有限数量的用户资源而设计。它允许多个线程在同一个时刻去访问同一个资源,但一般需要限制同一时刻访问此资源的最大线程数目
- 4.事件:
- 用来通知线程有一些事件已发生,从而启动后继任务的开始。
- 什么是内核线程和用户线程 ?
- 用户线程指不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。不需要用户态/核心态切换,速度快,操作系统内核不知道多线程的存在,因此一个线程阻塞将使得整个进程(包括它的所有线程)阻塞。由于这里的处理器时间片分配是以进程为基本单位,所以每个线程执行的时间相对减少。
- 内核线程:由操作系统内核创建和撤销。内核维护进程及线程的上下文信息以及线程切换。一个内核线程由于I/0操作而阻塞,不会影响其它线程的运行。
- 内核线程和用户线程的区别 ?
- 1.内核支持线程是OS内核可感知的,而用户级线程是OS内核不可感知的。
- 2.用户级线程的创建、撤消和调度不需要OS内核的支持,是在语言(如ava )这一级处理的;而内核支持线程的创建、撤消和调度都需OS内核提供支持,而且与进程的创建、撤消和调度大体是相同的。
- 3.用户级线程执行系统调用指令时将导致其所属进程被中断,而内核支持线程执行系统调用指令时只导致该线程被中断。
- 4.在只有用户级线程的系统内,CPU调度还是以进程为单位,处于运行状态的进程中的多个线程,由用户程序控制线程的轮换运行,在有内核支持线程的系统内,CPU调度则以线程为单位,由OS的线程调度程序负责线程的调度。
- 5.用户级线程的程序实体是运行在用户态下的程序,而内核支持线程的程序实体则是可以运行在任何状态下的程序。
- 内核线程和用户线程有什么优缺点 ?
- 内核线程的优点:
- 1.当有多个处理机时,一个进程的多个线程可以同时执行
- 缺点:
- 1.由内核进行调度
- 内核线程的优点:
- 用户线程的优点:
- 1.线程的调度不需要内核直接参与,控制简单
- 2.可以在不支持线程的操作系统中实现。
- 3.创建和销毁线程、线程切换代价等线程管理的代价比内核线程少得多。
- 4.允许每个进程定制自己的调度算法,线程管理比较灵活。这就是必须自己写管理程序,与内核线程的区别
- 5.线程能够利用的表空间和堆栈空间比内核级线程多
- 6.同一进程中只能同时有一个线程在运行,如果有一个线程使用了系统调用而阻塞,那么整个进程都会被挂起。另外,页面失效也会产生同样的问题
- 缺点:
- 4.资源调度按照进程进行,多个处理机下,同一个进程中的线程只能在同一个处理机下分时复用
- 什么是僵尸进程,孤儿进程,守护进程?
- 僵尸进程有什么危害 ?
- 如何清理僵尸进程?
- 僵尸进程有什么危害 ?
- 什么是进程
- 第一章 进程线程
- 1.1 进程线程的基本概念
- 1.1.1 什么是进程,线程,彼此有什么区别
- 1:进程是资源分配的基本单位,是程序执行时的一个实例,在程序运行的时候创建
- 2:线程是程序执行的最小单位,是进程的一个执行流,一个线程由多个线程组成。
- 3:区别:二者皆可并发执行,进程有自己的独立的地址空间,进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据,使用相同的地址空间因此,CPU切换一个线程的花费远比进程小很多,同时创建一个线程的开销也比进程小很多。
- 1.1.3什么时候用进程,什么时候用线程
- 对资源的管理和保护要求高,不限制开销和效率时,使用多进程要求效率高,频繁切换时,资源的保护管理要求不是很高时,使用多线程。
- 1.1.4多进程、多线程同步(通讯)的方法:共享内存、管道、消息队列、信号
- 1:管道(pipe):管道这种通讯方式有两种限制,一是半双工的通信,数据只能单向流动,二是只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
- 2:信号量(semophore):信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
- 3:共享内存(shared memory):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 lPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。
- 1.1.5进程的空间模型
- 1.1.6进程线程的状态转换图什么时候阻塞,什么时候就绪
- 进程的五个状态:
- 创建状态
- 就绪状态
- 运行状态
- 阻塞状态
- 终止状态
- 状态的转换图
- 进程的五个状态:
- 1.1.7父进程、子进程的关系以及区别
- 父进程和子进程之间是通过进程创建机制产生的关系。在操作系统中,当一个进程创建另一个进程时,创建的进程被称为子进程,而创建子进程的进程被称为父进程。
- 关系:
- 父进程: 父进程是创建其他进程的进程。当一个进程调用创建进程的系统调用(例如fork()或CreateProcess()),它会生成一个新的进程,而这个新的进程就是它的子进程。
- 子进程: 子进程是由父进程创建的进程。子进程继承了父进程的一些属性和资源,例如文件描述符、环境变量等。子进程通常是在父进程的上下文中启动执行的。
- 区别:
- 资源继承: 子进程会继承父进程的资源,例如打开的文件描述符、全局变量等。这意味着子进程在创建后会有与父进程相同的资源副本。但请注意,这些资源在子进程和父进程中是独立的,互不影响。
- PID(进程标识符): 父进程和子进程具有不同的PID,这是用于在操作系统中唯一标识每个进程的数字。
- 执行位置: 子进程在创建后,可以从父进程继续执行,但也可以执行不同的程序。例如,在某些操作系统中,通过调用exec()函数,子进程可以执行另一个可执行文件,从而完全替换掉自己的代码。
- 进程关系: 子进程和父进程之间形成了一棵进程树的结构,其中每个子进程都是其父进程的直接子节点。当父进程终止时,它的所有子进程会被重新分配给其他进程作为新的父进程。
- IPC(进程间通信): 子进程和父进程之间可以通过IPC机制进行通信,例如管道、队列、共享内存等,这样可以实现进程间的数据交换和同步。
- 关系:
- 父进程和子进程之间是通过进程创建机制产生的关系。在操作系统中,当一个进程创建另一个进程时,创建的进程被称为子进程,而创建子进程的进程被称为父进程。
- 1.1.8什么是进程上下文、中断上下文
- 进程上下文是指进程在执行过程中的完整环境和状态信息,包括进程的寄存器内容、程序计数器(PC)、堆栈指针(SP)、打开的文件描述符、当前工作目录、内存映射、信号处理函数、进程标识符(PID)等。进程上下文记录了进程在执行过程中的所有状态,使得操作系统可以在不同进程之间进行切换,从而实现多任务并发执行。
- 中断上下文是指当中断事件发生时,处理器保存当前正在执行的程序(例如进程或内核代码)的环境和状态,然后转而执行中断处理程序(Interrupt Handler)。中断上下文包括处理器的寄存器内容、程序计数器(PC)、堆栈指针(SP)、中断号、中断原因等
- 总结来说,进程上下文是描述进程的执行环境和状态,使得操作系统可以在进程之间进行切换,实现多任务并发执行;中断上下文是描述中断事件发生时,处理器保存和切换的当前执行环境和状态,用于处理中断事件。两者都是操作系统实现多任务和响应外部事件的关键机制。
- 1.1.9一个进程可以创建多少线程,和什么有关
- 1:操作系统的限制: 操作系统对于每个进程所能创建的线程数量通常有一个限制。这个限制是由操作系统的设计和实现决定的。不同的操作系统可能有不同的线程数量限制。
- 2:系统资源: 线程是系统资源的消耗者。每个线程需要占用一定的内存空间用于堆栈、寄存器等。如果系统内存有限,那么进程能够创建的线程数量就会受到限制。
- 3:硬件资源: 线程的执行需要CPU资源。如果CPU核心数有限,那么同时运行的线程数量就会受到限制。
- 4:线程的类型: 不同类型的线程可能对系统资源的消耗不同。例如,用户线程和内核线程的资源消耗方式不同,可能导致线程数量上的差异。
- 5:编程语言和库的限制: 不同的编程语言和线程库可能对线程数量有自己的限制。例如,某些编程语言或库可能对线程的管理和创建有特定的限制。
- 1.1.1 什么是进程,线程,彼此有什么区别
- 1.2 并发,同步,异步,互斥,阻塞,非阻塞的理解
- 1.2.1什么是线程同步和互斥
- 1.2.2线程同步与阻塞的关系?同步一定阻塞吗?阻塞一定同步吗?
- 1.2.3并发,同步,异步,互斥,阻塞,非阻塞的理解
- 1.3 孤儿进程、僵尸进程、守护进程的概念
- 1.3.1基本概念
- 僵尸进程:是一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
- 僵尸进程是指一个已经终止(执行完成)的进程,但其父进程尚未调用 wait() 或 waitpid() 等系统调用来获取子进程的退出状态。因为父进程没有回收僵尸进程的资源,导致僵尸进程的进程表项仍然存在于系统中,占用了一些系统资源。但是,僵尸进程并不执行任何代码,只是保留其退出状态等信息。应该及时回收僵尸进程,否则过多的僵尸进程会导致系统资源的浪费。
- 孤儿进程:是因为父进程异常结束了,然后被1号进程init收养。
- 守护进程:是创建守护进程时有意把父进程结束,然后被1号进程init收养
- 僵尸进程:是一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
- 1.3.2如何创建守护进程:
- 1.3.3正确处理僵尸进程的方法
- 危害:僵尸进程是指一个已经终止(执行完成)的进程,但其父进程尚未调用 wait() 或 waitpid() 等系统调用来获取子进程的退出状态。因为父进程没有回收僵尸进程的资源,导致僵尸进程的进程表项仍然存在于系统中,占用了一些系统资源。但是,僵尸进程并不执行任何代码,只是保留其退出状态等信息。应该及时回收僵尸进程,否则过多的僵尸进程会导致系统资源的浪费。
- 如何清理僵尸进程:
- 僵尸进程的产生是因为父进程没有 wait() 子进程。所以如果我们自己写程序的话一定要在父进程中通过wait() 来避免僵尸进程的产生。
- 当系统中出现了僵尸进程时,我们是无法通过 kill 命令把它清除掉的。但是我们可以杀死它的父进程让它变成孤儿进程,并进一步被系统中管理孤儿进程的进程收养并清理。
- 1.3.1基本概念
- 1.1 进程线程的基本概念