第二章 进程管理
2.1进程的基本概念 2.1.1 程序的顺序执行及特征 一、程序执行有固定的时序。(图2-1p27) 二、特征: 顺序性、封闭性、可再现性 2.1.1 程序的顺序执行及特征 一、程序执行有固定的时序。(图2-1p27) 二、特征: 顺序性、封闭性、可再现性 I1 C1 P1 I2 C2 P2
2.1.2前趋图定义 有向无循环图 表示方式: (1)p1--->p2 (2)--->={(p1,p2)| p1 必须在p2开始前完成} (图2-2 P27) 节点表示:一条语句,一个程序段,一进程。 P1 P1 P1 P1
2.1.3 程序的并发执行 一、多个程序的并发执行(可能性分析) I1 I2 I3 I4 C1 C2 C3 C4 P1 P2 P3 P4 t
程序的并发执行(2) 二、特征 间断性 失去封闭性:主要由共享资源引起 不可再现性:P29例,设N的初值为n。 有2个循环程序A和B,它们共享一个变量N,程序A每执行一次时,都要做N:=N+1; B则每次要执行Print(N), 然后再做N:=0. 若程序A,B以不同的速度运行有以下三种不同的结果
程序的并发执行(3) N:=N+1在print(N)和N:=0之前,则N值分别为n+1,n+1,0.
2.1.4进程的特征和状态 1. 进程的特征和定义 一、定义: 程序的一次执行过程 1.结构特征 进程:由程序段、数据段及进程控制块三部分构成,总称“进程映像”。 2.动态性 由“创建”而产生,由“调度”而执行;由得不到资源而阻塞;由撤消而消亡。(而程序是静态的)。
2.1.4进程的特征和状态(2) 3.并发性 只有建立了进程,才能并发执行。 4.独立性。 独立运行,独立获得资源。 5.异步性:(间断性)
2.1.4进程的特征和状态(3) 2. 进程的三种基本状态(图2-5p31) 就绪状态 执行状态 阻塞状态 就绪 阻塞 执行 时间片完 I/O完成 进程调度 阻塞 执行 I/O请求 图2-5 进程的三种基本状态及其转换
2.1.4进程的特征和状态(4) 3. 挂起状态(被换出内存的状态) 引入原因 终端用户请求 父进程请求 负荷调节需要 操作系统需要 进程状态的转换(图2-6) 活动就绪 静止就绪 活动阻塞 静止阻塞 静止就绪 活动就绪 静止阻塞 活动阻塞
图2-6 具有挂起状态的进程状态图 执行 挂起 请求I/O 激活 活动 静止 就绪 就绪 挂起 释放 释放 激活 活动 静止 阻塞 阻塞
实验 写一个程序描述进程状态迁移过程。 要求: 提供导致进程状态变化的调用接口,包括创建、删除、调度、阻塞、时间到、挂起、激活等。 实现进程列表显示的接口。 注:这里设计的进程是一个假设的对象实体,是由程序自己创建和删除,不是系统维护的进程。
2.1.5进程控制块 pid 1.进程控制块的作用 进程状态 是进程存在的唯一标志; PCB(process control block)常驻内存 2.进程控制块中的信息 标识、处理机状态,进程调度信息,进程控制信息 pid 进程状态 现场 优先级 阻塞原因 程序地址 同步机制 资源清单 链接指针
2.1.5进程控制块(2) 3.PCB的组织 链接(p33图2-7) 索引(p34图2-8) PCB1 4 PCB2 3 PCB3 PCB4 PCB4 8 PCB5 PCB6 7 PCB7 9 PCB8 PCB9 1 执行指针 就绪队列指针 阻塞队列指针 空闲队列指针
struct task_struct * task; struct wait_queue * next; }; 等待队列示例 struct wait_queue { struct task_struct * task; struct wait_queue * next; }; PCB PCB PCB
2.1.5进程控制块(3) PCB1 3.PCB的组织 PCB2 索引(p34图2-8) PCB3 PCB4 执行指针 PCB5 PCB6 就绪表指针 阻塞表指针
补充 PCB和进程的代码数据放在一起吗? 系统态和用户态 系统空间和用户空间 系统调用和普通调用的区别? 系统调用会引起从用户态进入核心态
2.2 进程控制 2.2.1 进程的创建 一、进程图: 描述了进程的家族关系:(P34 图2-9) 2.2 进程控制 2.2.1 进程的创建 一、进程图: 描述了进程的家族关系:(P34 图2-9) 子进程可继承父的资源,撤消时应归还给父进程,父的撤消会撤消全部子进程。 二、引起创建进程的事件: 1.用户登录: 为终端用户建立一进程 2.作业调度:(不是进程调度) 为被调度的作业建立进程 3.提供服务: 如要打印时建立打印进程
2.2.1 进程的创建(2) 4.应用请求: 由应用程序建立多个进程 三、进程的创建:(creat原语) 2.2.1 进程的创建(2) 4.应用请求: 由应用程序建立多个进程 三、进程的创建:(creat原语) 1.申请空白PCB(一个系统的PCB是有限的) 2.为新进程分配资源(不同于一般的分配,PCB-LIST在一个特殊区域) 3.初始化PCB 4.将新进程插入就绪队列。
2.2.2 进程的终止 一、引起进程终止的事件 1.正常结束:如Halt、logoff 2.2.2 进程的终止 一、引起进程终止的事件 1.正常结束:如Halt、logoff 2.异常结束:如Protect error、overtime等 3.外界干预: a.系统员kill进程; b.父进程终止; c.父进程请求。
2.2.2 进程的终止(2) 二、进程的终止过程 (1)检查进程状态; (2)执行态――>中止,且置调度标志为真。 2.2.2 进程的终止(2) 二、进程的终止过程 (1)检查进程状态; (2)执行态――>中止,且置调度标志为真。 (3)有无子孙需终止。 (4)归还资源给其父进程或系统。 (5)从PCB队列中移出PCB.
2.2.3 进程的阻塞与唤醒 一、引起进程阻塞和唤醒的事件 1.请求系统服务而得不到满足时,如问系统请求打印。 2.2.3 进程的阻塞与唤醒 一、引起进程阻塞和唤醒的事件 1.请求系统服务而得不到满足时,如问系统请求打印。 2.启动某种操作而需同步时:如该操作和请求该操作的进程需同步运行(即非异步操作)。 3.新数据尚未到达:如进程A写,进程B读,则A未写,完B不能读。 4.无新工作可做。
2.2.3 进程的阻塞与唤醒(2) 二、进程阻塞过程: 是进程自身的一种主动行为 a.调block原语 2.2.3 进程的阻塞与唤醒(2) 二、进程阻塞过程: 是进程自身的一种主动行为 a.调block原语 b.停止执行,修改PCB入阻塞队列(一个或多个),并转调度。 三、唤醒过程 其它相关进程完成。 a.wakeup原语 b.修改PCB,入就绪队列 可见,有block原语,在其它进程中就应有wakeup原语。
2.2.4 进程的挂起与激活 一、进程的挂起过程 由进程自己或其父进程调suspend原语完成,将该进程PCB移到指定区域,注意状态的改变,有可能要重新调度。 二、进程的激活过程。 active原语(如在外存,调入内存,改变状态,根据情况看是否调度,如抢先或非抢先)。 阻塞、唤醒一般由OS实现,而挂起与激活可由用户干预。
2.3进程同步 同步:并发进程在执行次序上的协调,以达到有效的资源共享和相互合作,使程序执行有可再现性。
2.3.1 进程同步的基本概念 1.两种形式的制约关系 资源共享关系:(进程间接制约) 需互斥地访问临界资源。 2.3.1 进程同步的基本概念 1.两种形式的制约关系 资源共享关系:(进程间接制约) 需互斥地访问临界资源。 相互合作关系:(进程直接制约) 2. 临界资源:(一次仅允许一个进程访问的资源) 引起不可再现性是因为临界资源没有互斥访问。
生产者-消费者问题 Var n, integer; Type item=…; var buffer:array[0,1,…,n-1] of item; in, out: 0,1, …, n-1; counter: 0,1,…,n;
生产者-消费者问题 producer: repeat … produce an item in nextp; while counter=n do no-op; buffer[in]:=nextp; in:=(in+1)mod n; counter:=counter+1; until false; consumer: repeat while counter=0 do no-op; nextc:=buffer[out]; out:=(out+1) mod n; counter:=counter-1; consumer the item in nextc; until false;
生产者-消费者问题(2) 设counter的初值为5 register1:=counter; register2:=counter; register1 :=register1+1; register2:=register2-1; counter :=register1; counter :=register2; register1:=counter; (register1:=5) register1 :=register1+1; (register1:=6) register2:=counter; (register2:=5) register2 :=register2-1; (register2:=4) counter :=register1; (counter:=6) counter :=register2; (counter:=4)
3. 临界区 定义:进程访问临界资源的那段代码。 访问临界资源的描述: 进入区:检查有无进程进入 临界区: 退出区:将访问标志复位 3. 临界区 定义:进程访问临界资源的那段代码。 访问临界资源的描述: 进入区:检查有无进程进入 临界区: 退出区:将访问标志复位 Repeat Entry section Critical section Exit section Until false
4.同步机制应遵循的准则 1.空闲让进 2.忙则等待 3.有限等待:应保证为有限等待,不会产生死等。 4.让权等待:不能进入临界区的执行进程应放弃CPU执行权。
2.3.2 信号量机制 1 整型信号量 是一个整型量,通过2个原子操作wait(s)和signal(s)来访问。 2.3.2 信号量机制 1 整型信号量 是一个整型量,通过2个原子操作wait(s)和signal(s)来访问。 Wait(s): while s<= 0 do no-op s:=s-1; Signal(s): s:=s+1;
2 记录型信号量 由于整型机制中会不断测试不满足“让权等待”而引入 type semaphore=record value:integer; 2 记录型信号量 由于整型机制中会不断测试不满足“让权等待”而引入 type semaphore=record value:integer; L: list of process; end L:为进程链表,用于链接所有等待该类资源进程。 procedure wait(s) var s: semaphore begin s.value:=s.value –1; if s.value <0 them block (S,L)
2 记录型信号量(2) procedure signal (S) var s:semaphone begin 2 记录型信号量(2) procedure signal (S) var s:semaphone begin s.value:=s.vaule+1 if s.value<=0 then wakeup(s.L) end 用wait(s)和signal(s)实现同步与互斥。 在记录型信号量机制中: s.value初值:表示系统中某类资源的数目。 s.value<0:表该信号量链表中已阻塞进程的数目。
3 AND型信号量 当不用它时,有可能发生系统死锁。 死锁:在无外力作用下的一种僵持状态。 AND信号量例:P42. 特点:要么全分配,要么一个也不分配。
3 AND型信号量 process A: wait(Dmutex); wait(Emutex); process B: 若2进程交替执行,则死锁
3 AND型信号量 Swait(s1,s2,…,sn) if s1≥1 and …and sn ≥1 then for i:=1 to n do si:=si-1; endfor else place the process in the waiting queue with the first si found with si<1, and set the program count of this process to the beginning of swait operation end if Ssignal(s1,s2,…,sn) for i:=1 to n do si:=si+1; remove all the process waiting in the queue associated with si into the ready queue endfor
4 信号量集(略) 为提高效率而对AND信号的扩充。(P43) 三种特例: (1)Swait(S,d,d):允许每次申请d个资源。 (2)Swait (s,1,1):S>1,记录型信号量。 S=1时,互斥型信号量。 (3)Swait(s,1,0),可控开关,当时,允许进入,S<1时,不能进入。
2.3.3 信号量的应用 1.利用信号量实现互斥 var mutex: semaphore:=1 begin parbegin 2.3.3 信号量的应用 1.利用信号量实现互斥 var mutex: semaphore:=1 begin parbegin process1:begin repeat wait(mutex); critical setion signal(mutex); remainder section until false; end
1.利用信号量实现互斥(2) process2: begin repeat wait(mutex); critical setion signal(mutex); remainder section until false; end parend
2.利用信号量来描述前趋关系(1) S1 a b S2 c S3 d S4 S5 e g f S6 图2-10 前趋图举例
利用信号量来描述前趋关系(2) Var a,b,c,d,e,f,g:semaphore:=0,0,0,0,0,0,0; Begin parbegin begin S1; signal(a); signal(b); end; begin wait(a);S2; signal(c); signal(d); end; begin wait(b);S3; signal(e); end; begin wait(c);S4; signal(f); end; begin wait(d);S1; signal(g); end; begin wait(e); wait(f);wait(g);S6; end; parend end
2.4 经典进程同步问题 2.4.1生产者--消费者问题 2.4.2哲学家进餐问题 2.4.3读者--写者问题
一、利用记录型信号量解决生产者一消费者问题 mutex:使诸进程互斥地访问缓冲区(n个缓冲区) empty、 full:空、满缓冲区数量。 Var mutex,empty,full:semaphore:=1,n,0; buffer:array[0,1,…,n-1] of item; in, out: integer: =0,0; begin parbegin producer: begin repeat … Produce an item in nextp;
一、利用记录型信号量解决生产者一消费者问题 consumer:begin repeat wait(full); wait(mutex); nextc:=buffer(out); out:=(out+1) mod n; signal(mutex); signal(empty); Consumer the item in nextc; Until false; end parend wait(empty); wait(mutex); buffer(in):=nextp; in:=(in+1) mod n; signal(mutex); signal(full); Until false; end
二、利用AND信号量解决生产者——消费者问题 var mutex, empty, full: semaphore:=1,n,0; buffer:array[0,…,n-1] of item; in out: integer :=0,0; begin parbegin producer: begin repeat … produce an item in nextp; swait(empty, mutex); buffer(in):=nextp;
in:=(in+1) mod n; ssingal(mutex, full); Until false; End Consumer: begin repeat swait(full, mutex); nextc:=buffer(out); out:=(out+1) mod n; ssignal(mutex, empty); consumer the item in nextc; until false; end parend
2.4.2哲学家进餐问题 1.利用记录型信号量解决哲学家进餐问题 Var chopstick: array[0, …, 4] of semaphore; Repeat wait(chopstick[i]); wait(chopstick[(i+1)mod 5]); … eat signal(chopstick[i]); signal(chopstick[(i+1)mod 5]); think; Until false
2.4.2哲学家进餐问题 1.利用AND信号量解决哲学家进餐问题 Var chopstick: array[0, …, 4] of semaphore:=(1,1,1,1,1); processi Repeat think; Sswait(chopstick[(i+1)mod 5],chopstick[i]); eat Ssignal(chopstick[(i+1)mod 5],chopstick[i]); Until false
2.4.3 读者——写者问题 特点: 读进程可共享同一对象。 写进程不可共享同一对象。
一、利用记录型信号量解决读者——写者问题 var rmutex, wmutex: semaphore: =1,1; readcount:integer: =0; begin parbegin reader: begin repeat wait(rmutex); if readcount=0 then wait(wmutex); readcount:=readcount+1; signal(rmutex); … perform read operation
一、利用记录型信号量解决读者——写者问题 perform read operation … wait(rmutex); readcount:=readcount-1; if readcount=0 then signal(wmutex); signal(rmutex); until false; end
一、利用记录型信号量解决读者——写者问题 writer: begin repeat wait(wmutex) perform write operation; signal(wmutex) until false; end parend
二、信号量集解决读者——写者问题(略) var RN integer; L, mx: semaphore: =RN, q; begin parbegin reader: begin repeat swait(L,1,1); swait(mx,1,0); … perform read operation; ssignal(L,1); until false; end writer: begin
二、信号量集解决读者——写者问题(略) writer: begin repeat swait(mx,1,1; L,RN,0); perform write operation; ssignal(mx, 1); until flase; end parend
2.5管程机制 引入原因: 为了避免凡要使用临界资源的进程都自备同步操作wait(s)和signal(s).将同步操作的机制和临界资源结合到一起,形成管程。 2.5.1管程的基本概念 一、定义:一个数据结构和能为并发进程所执行的一组操作。 局部于管程的共享变量。 对该数据结构进程操作的一组过程。 对局部管程数据设置初值。 二、条件变量: x.y: x.wait; x.signal; x.queue
2.5.2利用管程解决生产者——消费者问题 一、建立管程:PC 包括:二过程: (1)put(item)过程; (2)get(item)过程 一变量:count≥n时满;≤0 时空 初始: in=out=count=0 Type producer-consumer=monitor var in,out,count:integer; buffer: array [0,…,n-1] of item; notfull, notempty: condition; procedure entry put (item) procedure entry get (item)
2.5.2利用管程解决生产者——消费者问题 Procedure entry put(item) begin if count ≥n then notfull.wait; buffer(in):=nextp; in:=(in+1)mod n count:=count+1; if notempty.queue then notempty.signal; end Procedure entry get(item) if count ≤ 0 then notempty.wait; nextc:=buffer(out); out:=(out+1)mod n count:=count-1; if notfull.queue then notfull.signal; Begin in:=out:=0; count:=0 end
2.5.2利用管程解决生产者——消费者问题 例: producer: begin repeat produce a item nextp PC. put (item); until false. End Consumer: begin PC.get(item); Consume the item in nextc; Until false end 可见,由管程来实现后,进程的同步更简单明了。
练习 a,b 两点间是一段东西向的单行车道,现要设计一个自动管理系统,管理规则如下:当ab间有车辆在行驶时同方向的车可以同时驶入ab段,但另一方向的车必须在ab段外等待;当ab之间无车时,到达a(或b)的车辆可以进入ab段,但不能从a,b点同时驶入;当某方向在ab段行驶的车辆使出了ab段且无车辆进入ab段时,应让另一方向等待的车辆进入ab段行驶。请用wait,signal工具对ab段实现正确管理。
答: Semaphore s, mutexab,mutexba Pab: Wait(mutexab) Countab++ If countab=1 then wait(s); Signal(mutexab) ….. wait(mutexab) countab- -; if countab=0 then signal(s) signal(mutexab);
答: Pba: wait(mutexba) countba=countba+1; If countba=1 then wait(s) enter; …… countba--; if countba=0 then signal(s) signal(mutexba);
2.6进程通信 概念:进程间的信息交换。 实例: 信号量机制(一种低级通信) 缺点:(1)效率低 (2)通信对用户不透明 高级通信特点: 效率高,通信实现细节对用户透明
2.6.1进程通信的类型 一、共享存贮器系统 1.基于共享数据结构的通信方式: produce-consume中的缓冲区,低效,不透明。 系统只提供了一共享存贮器,适于少量通信。 2.基于共享存储区的通信方式: 系统提供:共享存储区。 通信过程: (1)向系统申请一个或多个分区 (2)获得分区获后即可读/写. 特点:高效,速度快。
2.6.1进程通信的类型 二、消息传递系统(可用于异种机) 三、管道通信 (1)互斥 (2)同步 (3)对方是否存在 信息单位:消息(报文) 是目前的主要通信方式,分为直接通信方式、间接通信方式 实现:一组通信命令(原语),具有透明性---> 同步的实现。 三、管道通信 管道:连接一个读进程和一个写进程之间通信的共享文件。 功能:大量的数据发收。 注意: (1)互斥 (2)同步 (3)对方是否存在
2.6.2直接/间接通信方式(消息通信的2种方式) 一、直接 send(Receiver, message) receive(Sender, message) 例:解决生产—消费问题。 repeat … produce an item in nextp; send(consumer, nextp); until false; receive( producer, nextc); consumer the item in nextc;
2.6.2直接/间接通信方式(消息通信的2种方式) 二、间接(可以实现非实时通信) 优点:在读/写时间上的随机性 写进程――> 信箱(中间实体)――>读进程 原语 (1)信息的创建与撤消: 信箱名 属性(公用、私用、共享)(共享者名字) (2)消息的发送和接收 Send (mailbox, message) Receive (mailbox, message)
2.6.2直接/间接通信方式(消息通信的2种方式) 二、间接(可以实现非实时通信) 信箱类型 (1)私用:拥有者有读/写数,其它只有写权,(单向)存在期=进程存在期。 (2)公用:系统创建,双向,存在期=系统存在期。 (3)共享信箱:一般进程创建,并指明其共享者,是双向。 发送—接收进程之间的关系: (1)一对一关系; (2)多对一关系; (3)一对多关系; (4)多对多关系:公用信箱。
2.6.3消息传递系统中的几个问题 一、通信链路: (1)显式建立:(进程完成) (2)隐式建立:(系统完成) 链路类型: (1)由连接方法分:点—点链路,多点链路。 (2)由通信方式分:单向、双向。 (3)由容量分:无容量(无缓冲区)、有(有缓冲区)。
2.6.3消息传递系统中的几个问题 二、消息格式: 消息头:含控制信息如:收/发进程名,消息长度、类型、编号 消息内容: 定长消息:系统开销小,用户不便(特别是传长消息用户) 变长消息:开销大,用户方便。
2.6.3消息传递系统中的几个问题 三、进程同步方式 1.发送和接收进程阻塞(汇合) 用于紧密同步,无缓冲区时。 2.发送进程不阻塞,接收进程阻塞(多个) 相当于接收进程(可能是多个)一直等待发送进程,如:打印进程等待打印任务。 3.发送/接收进程均不阻塞 一般在发、收进程间有多个缓冲区时。
2.6.4 消息缓冲队列通信机制 一、数据结构 1.消息缓冲区 type message buffer =record sender: size: text: next:指向下一指针 2.PCB中应增数据项: type pcb=record mq 消息队列指针 mutex 消息队列互斥信息量 sm 消息队列资源信息量(表资源消息数)
2.6.4 消息缓冲队列通信机制 二、发送原语 procedure send(receiver, a) begin getbuf(a.size, i); i.sender:=a.sender; i.size:=a.size; i.text:=a.text; i.next:=0; getid(PCB set, receiver.j); wait(j.mutex); insert(j.mq, i); signal(j.mutex); signal(j.sm); end
2.6.4 消息缓冲队列通信机制 三、接收原语 procedure receive(b) begin j:=internal name; wait(j.sm); wait(j.mutex); remove(j.mq, i); signal(j.mutex); b.sender:=i.sender; b.size:=i.size; b.text:=i.text; end
2.6.4 消息缓冲队列通信机制 PCB(B) 进程B mq 进程A mutex sender :A send(B,a) sm send(B,a) receive(b) sender :A size :5 text:hello next:0 a b sender:A 发送区A sender:A size:5 size:5 接收区B text:Hello text:Hello
练习 试说明如果使用send_mailbox和receive_mailbox 原语实现打印文件的系统。欲打印的进程将要打印的文件名发送到邮箱printer,打印机假脱机将打印邮箱中出现名字的任何文件
//process wish to print Char filename[ ]; Status=send_mailbox(“printer”,filename); If (status< 0) { //failure} //print spooler char filename[ ] while (true) { status=receive_mailbox(“printer”,filename); if(status <0) {//failure} print(filename); }
2.7线程 2.7.1线程的基本概念 1.线程的引入 减少并发执行时的时空开销,进程的创建、撤消、切换较费时空,因它既是调度单位,又是资源拥有者。 线程是系统独立调度和分派的基本单位,其基本上不拥有系统资源,只有少量资源(IP,寄存器,栈),但共享其所属进程所拥有的全部资源。
2.7线程 2.7.1线程的基本概念 2.线程的属性 轻型实体 独立调度和分派的基本单位 可并发实体 共享进程资源 3.线程的状态 状态参数 寄存器状态、堆栈、运行状态、优先级、线程专有存储器、 信号屏蔽 线程的运行状态
2.7线程 2.7.1线程的基本概念 4.线程的创建和终止 5.多线程中的进程 拥有系统资源的基本单位,不再是一个开执行的实体。
2.7.2线程的同步和通信 1.互斥锁 阻塞方式 lock(mutex) 访问 unlock(mutex) 非阻塞方式 if(trylock) then else
2.7.2线程的同步和通信 2.条件变量 略 3.信号量机制 私用信号量(private semaphore) 作用域在一个进程中 公用信号量(public semaphore) 作用于多个进程间
2.7.3内核级和用户级线程 用户级线程不依赖于内核,内核级依赖内核,其创建、撤消和切换都由内核实现,在内核中为其保留一张线程控制块。 比较: 1.线程的调度和切换速度: 内核级线程切换类似于进程切换,但速度快于进程切换。 用户级线程切换通常发生在同一用户进程的诸线程间,无需进入内核,更快。
2.7.3内核级和用户级线程 2.系统调用(用户级线程对内核是以进程为单位;这时进入系统态,并阻塞调用者) 当一个进程含多个用户线程,其中某一个线程进行系统调用,由于内核不知道这些线程的存在,因此将进程阻塞。 当一个进程含多个系统线程,其中某一线程进行系统调用,则阻塞该线程,进程仍可运行。 3.线程执行时间(用户级以用户进程为单位;由内核分配) 用户级线程以进程为单位平均分配时间,对线程间并发执行并不有利。 系统级线程以线程为单位平均分配时间。
2.7.3内核级和用户级线程
思考 进程间通信和同一进程内线程间通信的效率?