进程
传统的程序本身是一组指令的集合,是一个静态实体,无法描述程序在内存中的执行情况,也就不能如实反映程序并发执行过程的特征。
进程是操作系统进行资源分配和高度的独立单位,是程序在计算机上的一次执行过程。进程是动态概念,它可以申请和拥有系统资源,也是活动的实体。
进程由程序段、数据段和进程控制块组成。
进程控制块:描述和控制程序运行的一个数据结构,也称为PCB。
程序段和数据段:分别存放进程运行的程序和需要的数据。
进程特征:并发性、动态性、异步性、独立性。
进行执行时间间断性,运行中的进程可能有三种状态:就绪状态、执行状态和阻塞状态。三种基本状态转换方式:阻塞->就绪,就绪->执行,执行->就绪,执行->阻塞。
程序是静态,进程是动态。程序作为一种资料长期永久存在,进程是有生命周期,是暂时存在的。同一程序可以对应多个进程。程序并能独立运行,作为资源分配和独立运行的基本单元都是进程。
Linux进程用一个task_struct数据结构来表示,它就是Linux进程的PCB。
进程控制块(PCB):进程状态、进程调度信息、进程标识符、进程通信信息、进程链接信息、进程相关的文件信息、进程时间信息、进程虚拟内存信息等。
Linux进程在内存中由三个部分组成:堆栈段、代码段和数据段。
Linux调度器将进程分为三个不同的类型:交互进程、批处理进程、监控进程(守护进程)。
fork进程
进程是操作系统进行资源分配和高度的独立单位,是程序在计算机上的一次执行过程。进程是动态概念,它可以申请和拥有系统资源,也是活动的实体。
fork创建进程
函数原型如下
1 |
|
父进程与子进程
- 掌握概念,什么是父进程,什么是子进程
除了0号进程(系统创建的)之外,linux系统中都是由其他进程创建的。创建新进程的进程,即调用fork函数的进程为父进程,新建的进程为子进程。 - fork函数不需要任何参数,对于返回值有三种情况
- 对于父进程,fork函数返回新建子进程的pid;
- 对于子进程,fork函数返回 0;
- 如果出错, fork 函数返回 -1。
父子进程共享资源
1.父子进程共享代码段(可读的)
父进程在创建子进程的时候,子进程会把父进程的地址空间里的数据段。和栈堆进行复制,但是没有复制代码段。
fork函数出错的情况
- fork函数返回值为-1即创建失败,有两种情况可能会导致fork 函数出错;
- 系统中已经有太多的进程存在;
- 调用fork函数的用户的进程太多。
进程间通信
- 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;
- 信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期 信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上, 该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,sigaction函数重新实现了signal函数);
- 报文(Message)队列(消息队列):消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
- 共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针其他通信机制运行效率较低设计的。往往与其它通信机制,如信号量结合使用, 来达到进程间的同步及互斥。
- 信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。
- 套接字(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix 系统上:Linux和System V的变种都支持套接字。
线程
线程通信方式
- 锁机制:包括互斥锁、条件变量、读写锁和自旋锁。
互斥锁确保同一时间只能有一个线程访问共享资源。当锁被占用时试图对其加锁的线程都进入阻塞状态(释放CPU资源使其由运行状态进入等待状态)。当锁释放时哪个等待线程能获得该锁取决于内核的调度。
读写锁当以写模式加锁而处于写状态时任何试图加锁的线程(不论是读或写)都阻塞,当以读状态模式加锁而处于读状态时“读”线程不阻塞,“写”线程阻塞。读模式共享,写模式互斥.
条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
自旋锁上锁受阻时线程不阻塞而是在循环中轮询查看能否获得该锁,没有线程的切换因而没有切换开销,不过对CPU的霸占会导致CPU资源的浪费。 所以自旋锁适用于并行结构(多个处理器)或者适用于锁被持有时间短而不希望在线程切换产生开销的情况。 - 信号量机制(Semaphore):包括无名线程信号量和命名线程信号量
- 信号机制(Signal):类似进程间的信号处理
- 屏障
线程间的通信开发中常用的方式
- 全局变量方式 对于标准类型的全局变量,我们建议使用volatile修饰符,它告诉编译器无需对该变量作任何的优化,即无需将它放到一个寄存器中,并且该值可被外部改变
- 参数传递方式 主线程在创建子线程时,可以通过传给线程函数的参数和其通信
- 消息传递方式
- 线程同步法 synchronize
Java主要线程通信方式
- 共享变量来做控制,synchronized加锁的线程的Object类的wait()/notify()/notifyAll()
- 共享变量来做控制,ReentrantLock类加锁的线程的Condition类的await()/signal()/signalAll()
- 共享变量来做控制,volatile使用,AtomicInteger,
- 通过IO管道进行线程间通信:1)字节流;2)字符流
- while轮询的方式
- CyclicBarrier,BlockingQueue等