a process is a program in execution
程通常还包括进程堆栈段(包括临时数据,如函数参数、返回地址和局部变量)和数据段(包括全局变量)。进程还可能包括堆 (heap),是在进程运行期间动态分配的内存。
两个进程可能与同一个程序相关,但可能被当做两个独立的执行序列,如一个用户可以调用多个浏览器程序的副本,虽然程序的文本段相同,但是数据段,堆栈段,堆不同。
Google浏览器Google Chrome每开一个新标签页面,都会在系统进程里加入一个Chrome.exe进程。一个标签占用一个进程,这就是防止一个其中一个页面或者拓展崩溃后,造成整个浏览器崩溃的问题。
进程是资源划分的最小单位,线程是任务划分的最小单位
一个进程可以包含多个线程
进程在执行过程中拥有独立的内存单元,而多个线程共享内存(资源),从而极大地提高了程序的运行效率。
线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
线程安全:如果多个线程共享同一段代码,那么同时运行的时候,如果没有相应的机制(例如锁机制),就会产生不确定的结果,这就是非线程安全的。因而线程安全就是指多线程之间同步运行的时候不会产生莫名其妙或者不确定的结果(由于多线程执行的顺序是不可见和不可预知的),或者,通俗点讲,多线程下的线程安全就是多个线程同步工作的情况下,运行的结果和单线程运行的情况下没有什么区别,大多数情况下,这就是线程安全的。
新的:进程正在被创建
运行:指令正在被执行
等待:进程等待某个事件的发生(如 νo完成或收到信号)
就绪:进程等待分配处理器
终止:进程完成执行
进程在操作系统内用进行控制块process control block(PCB)表示,它包含许多与一个特定进程相关的信息
进程状态:新的、就绪、运行、等待、停止等
进程编号: pid通常是一个整数值
程序计数器:计数器表示进程要执行的下个指令的地址
CPU寄存器:包括累加器、索引寄存器、堆战指针、通用寄存器和其他条件码信息寄存器。与程序计数器一起,这些状态信息在出现中断时也需要保存,以便进程以后能正确地继续执行
内存管理信息:根据操作系统所使用的内存系统,这类信息包括基址和界限寄存器的值、页表或段表
记账信息:这类信息包括 CPU时间、实际使用时间、时间界限、记账数据、作业或进程数量等。
I/O状态信息:这类信息包括分配给进程的 νo设备列表、打开的文件列表等。
进程切换借助pcb进行和恢复到原来状态
进程调度选择一个可用的进程(可能从多个可用进程集合中选择)到 CPU上执行
驻留在内存中就绪的、等待运行的进程保存在就绪队列 中
进程向一个共享设备(如磁盘)发送I/ O请求,由于系统有许多进程,磁盘可能会忙于其他进程的I/O请求,因此该进程可能需要等待磁盘。等待特定I/O设备的进程列表称为设备队列
调度队列通常用链表来实现,头节点指向链表的第一个和最后-个 PCB块的指针。每个 PCB包括一个指向就绪队列的下-个 PCB的指针域。
linux进程控制块通过结构体实现
long state; /* state of the process */ struct schedentity se; /* scheduling information */ struct taskstruct *parent; /* this process’s parent */ struct listhead children; /* this process’s children */ struct filesstruct *files; /* list of open files */ struct mmstruct *mm; /* address space of this process */
The kernel maintains a pointer —current—to the process currently executing on the system, as shown below
The ready queue and various I/O device queues are
长期调度程序(long-term scheduler) 或作业调度程序 (job scheduler)长期调度程序执行得并不频繁,在系统内新进程的创建之间可能有数分钟间
短期调度程序 (short-term scheduler) 或 CPU调度程序。短期调度程序必须频繁地为CPU选择新进程。
如果所有进程均是I/ O为主的,那么就绪队列几乎为空,从而短期调度程序没有什么事情可做。如果所有进程均是 CPU为主的,那么I/ O等待队列将几乎总为空,从而几乎不使用设备,因而系统会不平衡。为了达到最好性能,系统需要一个合理的I/O为主和 CPU为主的组合进程。
上下文切换:将 CPU切换到另一个进程需要保存当前进程的状态并恢复另一个进程的状态,这一任务称为上下文切换 (context switch)。进程上下文用进程的 PCB表示。当发生上下文切换时,内核会将旧进程的状态保存在其 PCB中,然后装入经调度要执行的并己保存的新进程的上F文。上下文切换时间是额外开销,因为切换时系统并不能做什么高用的工作。
统中一个进程能影响其他进程或被其他进程所影响,那么该进程是协作的。显然,与其他进程共享数据的进程为协作进程。
进程通信的原因
信息共享( infonnation sharing)
提高运算速度( computation speedup)
模块化( modularity)
方便 (convenience)
协作进程需要一种进程间通信机制 (interprocess communication, IPC)来允许进程相互交换数据与信息。
进程间通信有两种基本模式:(1)共享内存, (2) 消息传递
在共享内存模式中,建立起一块供协作进程共享的内存区域,进程通过向此共享区域读或写入数据来交换信息。
在消息传递模式中,通过在协作进程间交换消息来实现通信
操作系统通常会组织一个进程访问另外一个进程的数据,而共享内存取消了这个限制。为了使生产者进程与消费者进程并发执行需要一个缓冲区域。缓冲分为两种:有限缓冲和无限缓冲。
the consumer must wait if the buffer is empty,and the producer must wait if the buffer is full.
共享缓冲的实现
共享缓冲是通过循环数组和两个逻辑指针来实现的:in 和 out。变量 in指向缓冲中下一个空位; out 指向缓冲中的第一个满位。当in==out 时,缓冲为空;当(in+l) %BUFFER SIZE= out时,缓冲为满
#define BUFFERSIZE 10 typedef struct { ... }item; item buffer[BUFFERSIZE]; int in = 0; int out = 0;
生产者
while (true){ /* produce an item in nextproduced */ while (((in + 1)% BUFFERSIZE) == out) ; /* do nothing */ buffer[in] = nextproduced; in = (in + 1)% BUFFERSIZE; }
消费者
item nextconsumed; while (true){ while (in == out) ; /* do nothing */ nextconsumed = buffer[out]; out = (out + 1)% BUFFERSIZE; /* consume the item in nextconsumed */ }
消息传递有以下几种方式:
(1)管道:无名管道(pipe)和有名管道(FIFO)
(2)消息队列
(3)信号量
(4)套接字(socket)
参考:
http://www.cnblogs.com/linshui91/archive/2010/09/29/1838770.html
http://blog.csdn.net/21aspnet/article/details/6734329
个进程从管道一头写数据,另一个进程从管道另一头读数据,以实现它们之间通信的共享方式。通信方式是单向的。管道类型分为:无名管道、命名管道
1.发送进程可以源源不断的从pipe一端写入数据流,在规定的pipe文件的最大长度(如4096字节)范围内,每次写入的信息长度是可变的。
2.接收进程在需要时可以从pipe的另一端读出数据,读出单位长度也是可变的。
int do_pipe(int *fd);//创建管道 static int pipe_release(struct inode *inode, int decr, int decw);//管道释放
消息队列是比较高级的一种进程间通信方法,实现一个或多个进程间message传送,一个消息队列可以被多个进程所共享消息队列,是一个队列的结构,队列里面的内容由用户进程自己定义。实际上,队列里面记录的是指向用户自定义结构的指针和结构的大小。要使用message queue,首先要通过系统调用(msgget)产生一个队列,然后,进程可以用msgsnd发送消息到这个队列,消息就是如上所说的结构。别的进程用msgrcv读取。消息队列,是一个队列的结构,队列里面的内容由用户进程自己定义。
int msgget(key_t key, int msgflg);//获取一个存在的消息队列的ID,或者是根据跟定的权限创建一个消息队列。 int msgctl(int msqid, int cmd, struct msqid_ds *buf);//用来从msqid_ds中获取很多消息队列本身的信息。 int msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg);//用于向队列发送消息。 int msgrcv(int msqid, void *msgp, size_t msgsz, long int msgtyp, intmsgflg);//从队列中接收消息。
创建套接字 socket();
绑定本机端口 bind();
建立连接 connect();
接受连接 accept();
监听端口 listen();
数据传输 send(), recv()等
关闭套接字 close();
//Socket相关数据结构 struct sockaddr_in { short int sin_family; /*通信类型*/ unsigned short int sin_port; /*端口号,网络直接顺序*/ struct in_addr }