5.1. Linux下两个进程可以同时打开同一个文件,这时如下描述错误的是: 7
5.2. 在退出unix系统账户之后还需要继续运行某个进程,那么可用() 7
5.3. Linux 系统上同一个程序的多个进程实例共享一个 TCP 监听端口不正确说法? 8
5.4. int main(){fork()||fork();}共创建几个进程:___3__ 8
先来先服务
优先级
时间片轮转
多级反馈
Linux进程间通信:管道、信号、消息队列、共享内存、信号量、套接字(socket)
Linux线程间通信:互斥量(mutex),信号量,条件变量
临界区只在windows线程、信号只在Linux进程
Windows进程间通信:管道、消息队列、共享内存、信号量 (semaphore) 、套接字(socket)
Windows线程间通信:临界区(critical section)、互斥量(mutex)——实现线程互斥、
事件、信号量(semaphore)——实现线程间的同步。
进程A读取B进程中的某个变量(非共享内存),可行的方式有()
B进程向消息队列写入一个包含变量内容的消息,A进程从队列中读出
通过本地环路通信
如果A、B 非亲属,那么A通过命名管道把这个变量的地址发给B进程
如果 B是A 进程的子进程,那么B直接读取变量内容即可
A选项为消息队列的实现方式。
B选项为本地socket通信方式。
C选项为命名管道通信方式。不应该是变量地址而应该是变量值,给地址空间也是没有权限访问的。
D选项通过fork子进程的方式,但是二者的地址空间是各自独立的,子进程无法读取父进程的数据,故不可用。
(1)管道(Pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系或一个进程和另一个与它有共同祖先的进程之间进行通信。
(2)命名管道(named pipe):命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信,也是半双工的通信方式。命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建。
(3)信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;
(4)消息(Message)队列:消息队列是消息的链接表,存放在内核中并由消息队列标识符标识。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点
(5)共享内存:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问同一块内存空间。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
(6)内存映射(mapped memory):内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它。
(7)信号量(semaphore):信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程不同线程之间的同步手段。
(8)套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。
1、 临界区(CCriticalSection)
当多个线程访问一个独占性共享资源时,可以使用临界区对象。拥有临界区的线程可以访问被保护起来的资源或代码段,其他线程若想访问,则被挂起,直到拥有临界区的线程放弃临界区为止。具体应用方式:
1、 定义临界区对象CcriticalSection g_CriticalSection;
2、 在访问共享资源(代码或变量)之前,先获得临界区对象,
g_CriticalSection.Lock();
3、 访问共享资源后,则放弃临界区对象,g_CriticalSection.Unlock();
2、 互斥量(CMutex)
互斥对象和临界区对象非常相似,只是其允许在进程间使用,而临界区只限制与同一进程的各个线程之间使用,但是更节省资源,更有效率。
3、事件(CEvent)
事件机制,则允许一个线程在处理完一个任务后,主动唤醒另外一个线程执行任务。比如在某些网络应用程序中,一个线程如A负责侦听通信端口,另外一个线程B负责更新用户数据,利用事件机制,则线程A可以通知线程B何时更新用户数据。每个Cevent对象可以有两种状态:有信号状态和无信号状态。
Cevent类对象有两种类型:人工事件和自动事件。
在创建Cevent对象时,默认创建的是自动事件。
自动事件对象,在被至少一个线程释放后自动返回到无信号状态;
人工事件对象,获得信号后,释放可利用线程,但直到调用成员函数ReSet()才将其设置为无信号状态。
- CEvent( BOOL bInitiallyOwn=FALSE,
BOOL bManualReset=FALSE,
LPCTSTR lpszName=NULL,
LPSECURITY_ATTRIBUTES lpsaAttribute=NULL );
bInitiallyOwn: 指定事件对象初始化状态,TRUE为有信号,FALSE为无信号;
bManualReset:指定要创建的事件是属于人工事件还是自动事件。TRUE为人工事件,FALSE为自动事件;
后两个参数一般设为NULL,在此不作过多说明。
2、BOOL CEvent::SetEvent();
将Cevent类对象的状态设置为有信号状态。如果事件是人工事件,则Cevent类对象保持为有信号状态,直到调用成员函数ResetEvent()将其重新设为无信号状态时为止。如果为自动事件,则在SetEvent()后将事件设置为有信号状态,由系统自动重置为无信号状态。
3、BOOL CEvent::ResetEvent();
将事件的状态设置为无信号状态,并保持该状态直至SetEvent()被调用为止。由于自动事件是由系统自动重置,故自动事件不需要调用该函数。
一般通过调用WaitForSingleObject()函数来监视事件状态。
4、 信号量(CSemphore)
当需要一个计数器来限制可以使用某共享资源的线程数目时,可以使用“信号量”对象。CSemaphore类对象保存了对当前访问某一个指定资源的线程的计数值,该计数值是当前还可以使用该资源的线程数目。如果这个计数达到了零,则所有对这个CSemaphore类对象所控制的资源的访问尝试都被放入到一个队列中等待,直到超时或计数值不为零为止。
CSemaphore( LONG lInitialCount = 1,
LONG lMaxCount = 1,
LPCTSTR pstrName = NULL,
LPSECURITY_ATTRIBUTES lpsaAttributes = NULL );
lInitialCount:信号量对象的初始计数值,即可访问线程数目的初始值;
lMaxCount:信号量对象计数值的最大值,该参数决定了同一时刻可访问由信号量保护的资源的线程最大数目;
后两个参数在同一进程中使用一般为NULL,不作过多讨论;
一般是将当前可用资源计数设置为最大资源计数,每增加一个线程对共享资源的访问,当前可用资源计数就减1,只要当前可用资源计数大于0,就可以发出信号量信号。如果为0,则放入一个队列中等待。线程在处理完共享资源后,应在离开的同时通过ReleaseSemaphore()函数将当前可用资源数加1。
当有多个线程的时候,经常需要去同步这些线程以访问同一个数据或资源。例如,假设有一个程序,其中一个线程用于把文件读到内存,而另一个线程用于统计文件中的字符数。当然,在把整个文件调入内存之前,统计它的计数是没有意义的。但是,由于每个操作都有自己的线程,操作系统会把两个线程当作是互不相干的任务分别执行,这样就可能在没有把整个文件装入内存时统计字数。为解决此问题,你必须使两个线程同步工作。
是指散布在不同进程之间的若干程序片断,当某个进程运行其中一个程序片段时,其它进程就不能运行它们之中的任一程序片段,只能等到该进程运行完这个程序片段后才可以运行。如果用对资源的访问来定义的话,互斥某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
是指散布在不同进程之间的若干程序片断,它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。如果用对资源的访问来定义的话,同步是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是操作系统进行资源分配和调度的一个独立单位;
线程是进程的一个实体,是CPU调度和分派的基本单位,是比进程更小的能独立运行的基本单位。线程的划分尺度小于进程,这使得多线程程序的并发性高;
进程在执行时通常拥有独立的内存单元,同属一个进程的线程之间可以共享内存,共享进程所拥有的全部资源.提高了程序的运行效率。
(1)一个线程只能属于一个进程,必须有一个父进程,而一个进程可以有多个线程,但至少有一个线程。
(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。
(3)处理机分给线程,即真正在处理机上运行的是线程。
(4)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。线程是指进程内的一个执行单元,也是进程内的可调度实体.
(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位
(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行
(3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源.
(4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。
在windows中,一个进程由三个部分组成:进程控制块PCB、数据和程序。
在UNIX中,一个进程也由三个部分组成:进程控制块、数据段和共享正文段,并有其自身的不同含义。
进程运行时用到的数据以及工作区,构成了一个进程的数据段。要注意的是,如果进程执行的程序是不能被共享的,那么也把它归入到数据段中。
为了管理好进程的共享正文段,UNIX在内存专门开辟了一个text结构区域,形成正文段表text[ ]. 因此,划分进程为进程控制块、正文段、数据段可以实现共享正文,共享数据和可重入
交互进程——由一个shell启动的进程。交互进程既可以在前台运行,也可以在后台运行。
批处理进程——这种进程和终端没有联系,是一个进程序列。
监控进程(也称守护进程)——Linux系统启动时启动的进程,并在后台运行。
实时进程:
并发性:系统中多个进程可以并发执行,相互之间不受干扰。
动态性:进程都有完整的生命周期,在进程生命周期内,进程的状态是不断变化的,另外进程具有动态的地址空间
交互性:进程在执行过程中可能和其他进程发生直接或间接的交互操作,如进程的同步与互斥,需要一些进程处理机制
独立性:进程是一个相对完整的资源分配和调度的基本单位,各进程的地址空间是相对独立的,只有采用特定的通信机制才能实现进程间的通信。
异步性:每个进程都按照各自独立的不可预知的速度向前执行。
1) 新状态:进程已经创建,但未被OS接纳为可执行进程。(还没有申请到相应的资源)。
2) 就绪态:进程做好了准备,具备运行条件,但由于没有空闲CPU,而暂时不能运行 。
3) 执行状态:该进程正在执行,占有CPU,并在CPU上运行 。
4) 阻塞状态:因等待某一事件而暂时不能运行,如等待I/O完成,等待读盘结果。这时Linux内核将取得的处理器的控制权,并按照内核的调度算法决定将处理器分配给哪个进程。
5) 终止状态.
1. 为什么要分开就绪和阻塞状态
答:因为就绪态只需要等待处理机,而阻塞态可能在等待输入输出,即使分配给处理机也是徒劳,所以两状态图不妥。对于调度进程,只需要等待就绪队列里的进程,因为阻塞状态可以转换到就绪队列里去。
2. 问题:多个进程竞争内存资源
原因: 内存资源紧张,无就绪队列。
处理机空闲:I/O速度比处理机速度慢的多,可能出现全部进程阻塞等待I/O。
解决方法:
交换技术:换出一部分暂时不能运行的进程(阻塞进程)到外存(只换出程序和数据,PCB不换出去),以腾出内存空间,可以调用新进程来执行。
虚拟存储技术:每个进程只能装入一部分程序和数据
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但多进程的程序在进程切换时,耗费资源较大,效率要差一些。对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
用户级线程:主要解决上下文切换问题,它的调度算法和调度过程由用户自行决定,在运行是不需要内核支持
内核线程:允许不同进程中的线程按照同一相对优先级调度方法进行调度,从而发挥多处理器的并发优势。
轻量级线程:内核支持的用户线程,是内核线程的一种抽象对象
(1)易于调度。
(2)提高并发性。通过线程可方便有效地实现并发性。进程可创建多个线程来执行同一程序的不同部分。
(3)开销少。创建线程比创建进程要快,所需开销很少。
(4)利于充分发挥多处理器的功能。通过创建多线程进程(即一个进程可具有两个或更多个线程),每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。
由于每个进程都有自己的数据段,代码段和堆栈段,造成进程在进行切换时开销大,而线程可以对进程的内存空间和资源进行访问,并于同一进程的其他线程共享,因而线程的上下文切换开销小。
如果把进程理解为在逻辑上操作系统所完成的任务,那么线程表示完成该任务的许多可能的子任务之一。例如,假设用户启动了一个窗口中的数据库应用程序,操作系统就将对数据库的调用表示为一个进程。假设用户要从数据库中产生一份工资单报表,并传到一个文件中,这是一个子任务;在产生工资单报表的过程中,用户又可以输人数据库查询请求,这又是一个子任务。这样,操作系统则把每一个请求――工资单报表和新输人的数据查询表示为数据库进程中的独立的线程。线程可以在处理器上独立调度执行,这样,在多处理器环境下就允许几个线程各自在单独处理器上进行。操作系统提供线程就是为了方便而有效地实现这种并发性
一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为init,而init进程会循环地wait()已经退出的子进程。孤儿进程不会使系统资源耗光而不能产生新进程
一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。如果进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。
A.两个进程中分别产生生成两个独立的fd
B.两个进程可以任意对文件进行读写操作,操作系统并不保证写的原子性
C.进程可以通过系统调用对文件加锁,从而实现对文件内容的保护
D.任何一个进程删除该文件时,另外一个进程会立即出现读写失败
E.两个进程可以分别读取文件的不同部分而不会相互影响
F.一个进程对文件长度和内容的修改另外一个进程可以立即感知
D, 一般删除都是文件索引,如果两个文件同时打开同一个文件,一个线程执行删除操作,只要另一个线程不退出,就可以继续对该文件进行操作,一旦退出才找不到该文件的索引节点而报错。文件的删除是根据引用技术操作的,如果引用技术为0,则会删除
内核中,对应于每个进程都有一个文件描述符表,表示这个进程打开的所有文件。文件描述表中每一项都是一个指针,指向一个用于描述打开的文件的数据块———file对象,file对象中描述了文件的打开模式,读写位置等重要信息,当进程打开一个文件时,内核就会创建一个新的file对象。需要注意的是,file对象不是专属于某个进程的,不同进程的文件描述符表中的指针可以指向相同的file对象,从而共享这个打开的文件。file对象有引用计数,记录了引用这个对象的文件描述符个数,只有当引用计数为0时,内核才销毁file对象,因此某个进程关闭文件,不影响与之共享同一个file对象的进程.
awk
sed
crontab
Nohup
awk 对数据分析的,又称过滤器。可以进行样式装入、 流控制 、数学 运算符 、进程 控制语句 甚至于内置的变量和函数。
sed 编辑文件的
crontab 用于设置周期性被执行的指令
nohup 在注销后使用 nohup 命令运行后台中的程序。该命令可以在你退出帐户/关闭终端之后继续运行相应的进程。nohup就是no hang up 不挂起的意思
sed awk grep ,linux文本处理三剑客
每个进程都使用 SO_REUSEPORT 选项,然后绑定同一个地址和端口
每个进程分别绑定不同的网卡地址的同一端口
第一个进程先绑定到监听地址端口, 然后 fork 子进程共享使用
每个进程分别绑定一次, 但只有最后一个调用的进程才能收到数据
D是竞争调度的结果,而不是最后调用的进程收到数据。确实只有一个进程收到数据,但是是多个进程竞争连接请求。
A使用SO_REUSEPORT,绑定统一地址和端口。
B分别绑定不同的网卡地址的同一端口,TCP的四元组并不冲突。
C使用fork创建子进程共享,也没有问题。
一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。
子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。
fork()的参考:http://blog.youkuaiyun.com/jason314/article/details/5640969
考查的知识点:||短路功能,如果第一个为真的话,那么后面不再执行,如果为假,就会继续判断右边的 fork()的return会执行两次,一次在父进程,一次在子进程。且return后接下的代码分别会在各个进程继续执行。