试:(1)描述一个保证不会出现两个邻座同时要求吃饭的通信算法。(2)述一个既没有两邻座同时吃饭,又没有人饿死(永远拿不到筷子)的算法。在什么情况下,5个哲学家全部吃不上饭?答,(1)设信号量c[0]~c[4]初始值均为1.分别表示1号筷子被拿(1=0,1.2,3,4),send(I),第1个皙学家要吃饭BeginP(c[]),P(c[I+1 mod 5J),Eat,V(c[I+1 mod 5]);V(c[1]>,End:该过程能保证两邻座不同时吃饭,但会出现5个哲学家-一人拿一只筷子,谁也吃不上饭的死锁情况。(2)解决的思路如下:让奇数号的哲学家先取右手边的筷子,让偶数号的哲学家先取左手边的筷子。这样,任何一个哲学家拿到一只筷子以后,就已经阻止了他邻座的一个哲学家吃饭的企图,除非某个哲学家一直吃下去,否则不会有人会饿死。send(I):BeginIf I mod2==0then1P(c[1],P(c[1+1] mod 5))Eat,V(c[1]), V(c[1+1 mod 5])7elseP(c[1+1mod 5])P(c[1])EatV(e[I+1 mod 5])V(c[I)子End15.什么是线程?试述线程与进程的区别。答:线程是在进程内用于调度和占有处理机的基本单位.它由线程控制表、存储线程上下文的用户栈以及核心栈组成。线程可分为用户级线程、核心级线程以及用户/核心混合型:14
线程等类型。其中用户级线程在用户态下执行,CPU调度算法和各线程优先级都由用户设置,与操作系统内核无关。核心级线程的调度算法及线程优先级的控制权在操作系统内核。混合型线程的控制权则在用户和操作系统内核二者。线程与进程的主要区别有:(1)进程是资源管理的基本单位,它拥有自已的地址空间和各种资源,例如内存空间、外部设备等,线程只是处理机调度的基本单位,它只和其他线程一起共享进程资源,但自己没有任何资源。(2)以进程为单位进行处理机切换和调度时,由于涉及到资源转移以及现场保护等问题,将导致处理机切换时间变长,资源利用率降低。以线程为单位进行处理机切换和调度时,由于不发生资源变化,特别是地址空间的变化,处理机切换的时间较短,从而处理机效率也较高。(3)对用户来说,多线程可减少用户的等待时间,提高系统的响应速度。例如,当一个进程需要对两个不同的服务器进行远程过程调用时,对于无线程系统的操作系统来说需要顺序等待两个不同调用返回结果后才能继续执行,且在等待中容易发生进程调度,对于多线程系统面言,则可以在同一进程中使用不同的线程同时进行远程过程调用,从而缩短进程的等待时间。(4)线程和进程一样,都有自已的状态,也有相应的同步机制,不过,由于线程没有单独的数据和程序空间,因此,线程不能像进程的数据与程序那样,交换到外存存储空间。从而线程没有挂起状态。(5)进程的调度、同步等控制大多由操作系统内核完成,而线程的控制既可以由操作系统内核进行,也可以由用户控制进行。16.使用库函数clone()与pthread..create()在ILinux环境下创建两种不同执行模式的线程程序。答:Linux系统支持用户级线程和核心级线程两种执行模式,其库函数分别为pthread..create()和clone()。创建用户级线程和核心级线程的程序示例如下:(1)用户级线程编程示例:#include<pthread.h>void * ptest(void *arg)1printf("This is the new thread! In");rerurn(NULL),1main()tpthread.t tid,printe("This is theparent prucess!n"),pthread create(&tid,NUL.I.ptest.NULL),/*创建线程*】sleep();·15
return;7该程序通过调用pthread_create()创建一个用户级线程,其指针为tid,过程名为ptest.(2)核心级线程编程示例:#include<signal.h>#include<stdio.h>#include<stdlib.h>#inelude <fentl.h>#include<linux/unistd,h>#defineSTACKSIZE16384#define CSIGNALOx00000off/ * signal mask to be sent at exit */#define CLONE-VM0x00000100/ # set if VM shared between processes * /#define CLONE_FS0x00000200/ * set if info shared between processes * /#define CLONE_FILES0x00000400/ * set if files shared between processes # /#defineCLONE_SIGHAND0x00000800/*setif signal handlersshared/int show-same.vmtvoid cloned-process-start_here(void * data)1printf("child,Itgotargument %dasfdn",(int)data),show_same-vm -- 5;printf (child: It vm = %d In", show-same-vm),close((int)data),1int main ()1int fd,pid,fdopen("/dev/null",.RDWR),if(fd<o)(perror("/dev/null");exit(1),1printf ("smother:/t vm =%dn",fd);show-same-vm = 10,.16
printf("mother,tvm=%d/n",show-same_vm);pid = clone (cloned-process-starts-here,(void *)fd);if (pid < 0) perror (start-thread");exit(1),1sleep(1)printf ("mother,It vm =%dn,show-same-vm),if (write (fd,"c",1)<0)printf ('mother:t child closed our file descriptorIn"),1#include <signal. h>#include<stdio.h>#include <stdlib.h>#include <fcntl.h>#includelinux/unistd.h>#defineSTACKSIZE16384# define CSIGNALOx00oo0off/ * signal mask to be sent at exit #/#define CLONE.VM0x00000100/ set if VM shared between processes * /#define CLONE-FS0x00000200/ * set if info shared between processes * /#define CLONE_FILES0x00000400/ + set if files shared between processes * /#defineCLONE-SIGHAND0x00000800/ * set if signal handlers shared + /int clone(void(+fn)(void *), void *data)*创建核心线程*/tlong retval;void *+newstack;/ ** allocate new stack for subthread*/newstack = (void * *) malloc (STACKSIZE);if (1 newstack)return-l;/ **Set up the stack for child function, put the (void *)* argument on the stack..17:
*/newstack=(void**)(STACKSIZE+(char*)newstack)*--newstack=data+/ * Do clone () system call. We need to do the low-level stuff entirely in assembly as we're returning with a different* stack in the child process and we couldn't otherwise guarantee* that the program doesn't use the old stack incorrectly..**Parameters to clone()system call:%eax--NR-clone,clone systemcall number**%ebx - clone.flags,bitmap of cloned data*%ecx-new stack pointer for cloned child**In thisexample%ebx is CLONE-VMICLONE-FS|CLONE-FILES1* CLONE.SIGHAND which shares as much as possible tetween parent and* child. (We or in the signal to be sent on child termination into clone-flagss* SIGCHLD makes the cloned process work like a "normal" unix child*process)*The clone () system call returns (in %eax) the pid of the newly* cloned process to the parent, and o to the cloned process. If* an error occurs, the return value will be the negative errno..* In the child process, we witl doa "jsr'to the requested function and then do a "exit ()"system call which will terninate the child.*/ -asm--volatile-("int$0x80\n\t"/*Linux/i386systemcall*/"testl %0,%0/n/*I * check return value * /"ine lfln/t"I * jump if parent * /"call*%3//t"I * start subthread function * /"mavl%2%0nlt"int$0x80ln"/ * exit system call:exit subthread */:I"."a" (retval)"o"(-NR_clone),""(_NR-exit),"r"(fn),"b*(CLONE.VMICLONE.FSCLONE_FILES|CLONE.SIGHANDCLONE.SIGCHLD),"c"(newstack)),if (retral <0) (:18: