




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、广西师范大学计算机科学与信息工程学院操作系统实验书 操作系统课程实验 年级 2011 级 专业 计算机科学与技术(应用型) 指导教师 黄 玲 2012年9月15日欢迎进入操作系统实验!操作系统是计算机系统的核心和灵魂,通过实验,可以帮助我们掌握操作系统的精髓,真正做到深刻理解和融会贯通用。本学期实验30学时,安排如下:实验一、熟悉Linux环境(2学时,第4周)3实验二、Linux进程同步与通信(4学时,第5、6周)6实验三、进程管理模拟实验(6学时,第7、8、9周)14实验四、Linux线程死锁实验(2学时,第10周)30实验五、存储管理实验(6学时,第11、12、13周)34实验六、设备管
2、理实验(4学时,第14、15周)50实验七、文件系统管理实验(6学时,第16、17、18周)62上述实验,有的在Linux环境下执行,主要目的是学习Linux API的使用;其他的在Windows环境下执行,采用Visual Studio C+ 开发环境(较好的调试环境),实现模拟管理实验。建议Linux实验采用Ubutu 8 (及以上版本),其内核为Linux2.6。可以从Ubuntu网站下载光盘镜像并刻录安装,网址: 。Ubuntu中文论坛: 。 安装好Ubuntu后,进入其终端,可以在命令行界面运行Linux指令。实验一、熟悉Linux环境(2学时,第4周)1. 实验目的熟悉Linux的
3、基本命令、C开发环境、程序执行。2. 实验环境Ubuntu 8.03. 实验内容3.1 熟悉Linux界面进入ubuntu,进入终端,执行所下述命令,观察结果:ls 、cat、cp、mv、rm、mkdir、cd、rmdir、man、ps、kill 进入终端:应用程序-附件-终端 。为了方便,可以把终端图标放到桌面上。命令输入提示符$表示当前处于普通用户状态,命令输入提示符#表示当前处于超级用户状态。有关Linux命令,可以参看附件“Linux常用命令.doc”,也可以到网上查找。按键CTRL+C可以中断命令的执行。3.2 Linux下C程序的编写及其执行(1)一般性步骤:第一步,使用文本编辑器
4、编辑后缀为.c的源程序。进入文本编辑器:应用程序-附件-文本编辑器。(为了方便,可以把文本编辑器放在桌面)第二步,进入终端的命令行界面,在源程序所在目录,编译源程序,一般命令如下:gcc o 目标文件名 源程序文件名第三步,如果没有错误,在当前目录下,运行目标程序: ./目标文件名更多Linux环境安装、实验编写,可参考书籍: Linux操作系统实验教程费翔林 主编 高等教育出版社 更多编写Linux系统的C程序,请查阅Linux C 函数库。推荐参考书: Linux C 函数库参考手册 徐千洋 中国青年出版社或请查看附件“Linux C 函数库说明.pdf” 更多的linux命令,请查阅网络
5、或者书籍。建议参考书: Linux应用与开发典型实例精讲 邱铁 清华大学出版社(2)、编辑、编译链接、执行下面C语言程序:父进程创建一个子进程,并等待子进程结束;子进程调用execve启动shell的ps命令,查看系统当前的进程信息。#include <unistd.h>#include <stdio.h>#include <stdlib.h>main() pid_t pid; char* str; char* path="/bin/ps" char* argv5="ps","-a","-
6、x",NULL; if (pid=fork()<0) /创建子进程 printf("创建子进程错误n"); exit(0); else if(pid=0) /以下为子进程代码: printf("由子进程运行ps命令,以查看系统当前进程信息。n"); if (execve(path,argv,0)<0) /子进程执行ps命令文件 printf("子进程执行错误n"); exit(0); printf("子进程成功执行n"); exit(0); /子进程结束 / pid>0时继续父进程执行(
7、pid为子进程号): wait(); /父进程等待子进程结束 printf("父进程退出!n"); exit(0); /父进程结束函数说明: (1)、pid_t fork(void) 创建子进程。如创建成功,在父进程返回子进程代码,在子进程则返回0。fork()创建的子进程与父进程运行于不同的地址空间,即父子各有独立空间,但子进程会复制父进程的资源(如同一份代码,打开文件等等)。父子进程之间的通信只能通过共享内存、消息、管道等方式进行。(2)、 pid_t wait() 暂停当前进程的执行,直到有信号来或者子进程结束。(3)、 void exit(int status) 正
8、常结束当前进程,并把参数status返回给父进程(4)、 int execve(const char* filename,char* const argv,char* const envp)执行参数filename字符串所代表的文件路径,argv传递给执行文件,envp为执行文件需要的新环境变量。如执行文件能成功执行则函数不会返回,执行失败返回-1。(5)、 pid_t vfork(void)创建子进程。vfork()不同fork()。vfor()创建的子进程与父进程共享同一地址空间,即子进程完全运行在父进程的地址空间上,子进程对虚拟地址空间任何数据的修改,父进程可见。但父进程创建子进程之后,
9、父进程会被阻塞,直到子进程执行exec()或exit()。更多的函数说明,请查看附件“Linux C 函数库说明.pdf”在源程序所在目录下编译连接:(假设上述源程序文件名myc.c,目标文件名myexe)gcc o myexe myc.c运行目标程序: ·/myexe3.3 查看进程 在一个命令终端1执行下述程序:#include <unistd.h>#include <stdio.h>main() long k; k=0; printf("nprocess ID=%d 中断:ctrl+c",(int)getpid(); while(1)
10、 sleep(1); printf("n%d",k+); 打开另外一个终端2,执行命令:ps -a -l观察上述进程相关内容,并用kill命令终止它。 实验二、Linux进程同步与通信(4学时,第5、6周)1、实验目的 理解进程的高级通信;理解通过信号量实现进程的同步。2、实验环境Ubuntu 8.03、实验内容3.1 观察Linux进程通信下面代码实现两个进程之间通过共享内存通信。#include <unistd.h>#include <sys/ipc.h>#include <stdlib.h>#include <sys/shm.
11、h>#define KEY 1234#define SIZE 64main() pid_t pid; /进程号 int shmid; /共享内存标识号 char* shmaddr; /共享内存的起始地址 shmid=shmget(KEY,SIZE,IPC_CREAT|0600); /创建共享内存shmid,大小为SIZE. if (pid=fork()<0) printf("创建子进程失败n"); exit(0); else if(pid=0) /子进程 shmaddr=(char*)shmat(shmid,NULL,0); 子进程绑定到共享内存shmid st
12、rcpy(shmaddr,"Hello!n"); /使用共享内存 shmdt(shmaddr); /断开与共享内存的连接 exit(0);/父进程: sleep(3); /等子进程完成对共享内存操作 shmaddr=(char*)shmat(shmid,NULL,0);/ 父进程绑定到共享内存shmid printf("%s",shmaddr); /使用共享内存 shmdt(shmaddr); /父进程断开与共享内存的连接 shmctl(shmid,IPC_RMID,NULL);/删除共享内存 exit(0); 本实例函数说明:(1) int shmge
13、t(key_t key,int size,int shmflg)配置共享内存。key用于获取共享内存识别代号,size为共享内存大小,shmflg指明共享内存的建立特征。返回共享内存标识号。(2) int shmctl(int shmid,int cmd,struct shimd_ds* buf)控制共享内存的操作。Shmid为共享内存标识号,cmd为操作命令,如IPC_RMID删除共享内存及其数据结构,buf为缓冲区。(3) void shmat(int shmid,const void * shmaddr,int shmflg)连接到共享内存。shmid为共享内存标识号,shmaddr为连
14、接地址形成方式,若为NULL,由核心自动选择一个地址,shmflg为操作标记。返回已连接好的地址。(4) int shmdt(const void *shmaddr)断开共享内存连接。Shmaddr为先前shmat()返回的地址。3.2 Linux进程同步实验要求:一个生产者向一个缓冲区发消息,每当发出一个消息后,要等待三个消费者都接收这条消息后,生产者才能发送新消息。用信号量和P、V操作,写出他们同步工作的程序。(提示:可以把缓冲区看作是三个缓冲块组成的缓冲区,生产者等到这三个缓冲块为空时,才发送新消息到这个缓冲区。每个消费者从一个缓冲块取走数据。)学习例子: 一个生产者进程不断向数组添加数
15、据(写入100次),两个消费者进程从数组中读取数据并求和。下面给出了基于信号量解决生产者-消费者问题的程序。创建了fullid、emptyid、mutxid三个信号量,供进程间同步访问临界区,同时建立四个虚存区:array用于生产者、消费者之间的共享数据,sum保存当前求和结果,set和get分别记录当前生产者进程和消费者进程的读写次数。程序流程图: main进程执行流程图:创建虚拟主存区初始化虚拟主存创建信号量初始化信号量创建一个生产者进程创建第一个消费者进程创建第二个消费者进程退出生产者进程执行流程图:I=0I<100? N Y对信号量执行P操作退出将数据放入缓冲区对信号量执行V操作
16、I=I+1消费者进程执行流程图: 条件为真 Y对信号量执行P操作 退出是否取完数据? Y N取数据并相加 显示求和结果是否取完数据? Y N对信号量执行V操作休眠一下#include <sys/mman.h>#include <sys/types.h>#include <linux/sem.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <errno.h>#include <time.h>#define MAXSEM
17、 5/声明三个信号灯IDint fullid;int emptyid;int mutxid;int main() struct sembuf P,V; /对信号量操作时需要的数据结构 union semun arg; /对信号量操作时需要的数据结构/声明虚拟主存 int *array; int *sum; int *set; int *get;/创建虚拟主存。即变量作为共享虚拟主存实现。 array = (int *)mmap(NULL , sizeof( int )* MAXSEM,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0); su
18、m = (int *)mmap(NULL , sizeof( int),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0); get = (int *)mmap(NULL , sizeof( int),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0); set = (int *)mmap(NULL , sizeof( int),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0); *sum = 0; /初始化变量 *get = 0; *s
19、et = 0; /创建信号量 fullid= semget(IPC_PRIVATE,1,IPC_CREAT|00666); /该信号量用于消费者获取数据 emptyid=semget(IPC_PRIVATE,1,IPC_CREAT|00666); /该信号量用于生产者获空闲缓冲区 mutxid=semget(IPC_PRIVATE,1,IPC_CREAT|00666); /该信号量用于对缓冲区的互斥 /为信号灯赋初值 arg.val = 0; if(semctl(fullid , 0 , SETVAL , arg) = -1) perror("semctl setval error&
20、quot;); arg.val = MAXSEM; if(semctl(emptyid , 0 ,SETVAL , arg) = -1) perror("semctl setval error"); arg.val = 1; if(semctl(mutxid , 0 ,SETVAL , arg) = -1) perror("setctl setval error"); /初始化P,V操作 V.sem_num=0; V.sem_op =1; V.sem_flg=SEM_UNDO; P.sem_num=0; P.sem_op =-1; P.sem_flg=S
21、EM_UNDO; /生产者进程 if(fork() = 0 ) int i = 0; while( i < 100) semop(emptyid , &P ,1 ); /申请空闲缓冲区 semop(mutxid , &P , 1); /申请对缓冲区的互斥操作 array*(set)%MAXSEM = i + 1; /放入数据到缓冲区 printf("Producer %dn", array(*set)%MAXSEM); (*set)+; semop(mutxid , &V , 1); /释放信号量 semop(fullid , &V ,
22、 1); i+; sleep(10); printf("Producer is over"); exit(0); else /ConsumerA 进程 if(fork()=0) while(1)if(*get = 100) break;semop(fullid , &P , 1); /申请数据 semop(mutxid , &P , 1);/申请对缓冲区的互斥操作 *sum += array(*get)%MAXSEM; /取走数据 printf("The ComsumerA Get Number %dn", array(*get)%MAX
23、SEM ); (*get)+; if( *get =100) printf("The sum is %d n ", *sum); semop(mutxid , &V , 1); /释放信号量 semop(emptyid , &V ,1 ); sleep(1); printf("ConsumerA is over"); exit(0); else /Consumer B进程 if(fork()=0) while(1)if(*get = 100) break; semop(fullid , &P , 1); semop(mutxid
24、, &P , 1); *sum += array(*get)%MAXSEM; printf("The ComsumerB Get Number %dn", array(*get)%MAXSEM ); (*get)+; if( *get =100) printf("The sum is %d n ", *sum); semop(mutxid , &V , 1); semop(emptyid , &V ,1 ); sleep(1); printf("ConsumerB is overn"); exit(0); re
25、turn 0;实例说明:1)、Linux中的信号量操作(1)打开一个现有信号量或者创建一个新信号量集合:int semget(key_t key,int nsems,int flag)key为键值,若为IPC_PRIVATE,表明需要创建一个新的、唯一的信号量集合对象;nsems指定创建/打开的信号量集合中,信号量的数目;flag指定创建/打开方式,取值IPC_CREAT|00666表明,若不存在key值的信号量则创建,信号量的权限与一般文件的一样。返回信号量集合描述字。(2)信号量值操作(P、V操作):int semop(int semid,struct sembuf* sops,unsig
26、ned nsops)semid为信号量集合描述字;sembuf指向类型为sembuf的数组;nsops为数组大小。其中:struct sembuf ushort sem_num; /在数组中信号量的索引值 short sem_op; /信号量操作值(正数为V操作,负数为P操作) short sem_flg; /操作标志; 上述结构体变量用于表示信号量具体操作。(3)信号量属性操作:(如设置信号量初值)int semctl(int semid,int semnum,int cmd,union semun arg)semid为信号量集合描述字;semnum为将要操作的信号量索引号;cmd为操作类型
27、,SETVAL表示设置semnum所代表的信号量值为arg.val;arg为操作参数。其中:union semun /联合体,指下面的变量共用同一个空间 int val; /SETVAL的值 struct semid_ds *bus; ushort *array; struct seminfo* _buf; void* _pad;2)、建立内存映射void mmap(void start,size_t length,int prot,int flags,int fd,off_t offset )该函数用于将某个文件内容映射到内存,对该区域的读写就是对文件内容的读写。在该实例中用来创建可以被共享
28、的主存空间。 start指向对应的虚拟内存起始地址,若为NULL表示由系统自动选定地址;length内存长度;prot为保护方式,PROT_READ为读,PROT_WRITE为写,MAP_SHARED为共享,MAP_ANONYMOUS为匿名映射(不涉及文件),fd为-1,表示不涉及文件;fd为文件描述字,-1表示不使用文件;offset为文件内偏移。返回虚拟内存起始地址(逻辑地址)。 由于父子进程的亲缘关系,父进程先调用mmap(),后调用fork()。在fork()之后,子进程继承父进程匿名映射后地址空间,同样也继承mmap()返回的地址。这样,父子进程就可以通过映射区进行通信了。mmap(
29、)返回的地址由父子共同维护,这是具有亲缘关系进程实现内存共享的方式。更多的函数请查阅Linux C 函数库实验三、进程管理模拟实验(6学时,第7、8、9周)1、实验目的 理解进程控制、进程调度、进程同步的原理2、实验环境Windows的Visual Studio C+3、 实验内容进程管理模拟实验要求:阅读后面的C语言进程管理代码,增加“创建进程”、“撤销进程”两个控制操作。进程管理系统描述: 本系统实现了进程调度、进程控制、进程同步等功能。进程调度程序负责为各个进程分配处理机;时间片中断处理程序模拟时间片中断;控制机构包括阻塞和唤醒操作;同步机构采用信号量和P、V操作。本系统设计了三个并发进
30、程。进程0完成5次计算:s1+;s2+; 进程1完成5次计算:s2+;s1+; 进程2完成5次计算:s2+ 。s1、s2需要互斥访问。进程状态有5种:'e'-执行态 ' r'-高就绪态 't'-低就绪态'w'-等待态 'c'-完成态。进程调度算法采用抢占式优先级法。各个进程的优先数通过键盘输入静态设置。调度程序每次总是选择优先数最小(优先权最高)的就绪进程投入执行。先从r状态进程中选择,再从t状态中选择。初始每个进程均为高就绪状态r。如果执行进程的时间片到,则转为低就绪状态t,并重新调度;如果执行进程因P操作被阻塞
31、,则重新调度;如果执行进程唤醒某个阻塞进程,则重新调度(如被唤醒进程的优先权高,则剥夺现行进程执行权);如果执行进程结束,则重新调度。系统分时执行各个进程,三个进程的执行概率为33%。通过产生随机数x模拟时间片。以下为各个进程执行时间片到限、产生时间片中断的条件:process0: 随机数x33%process1: 33%随机数x66%process2: 随机数x66%对临界资源s1、s2的访问。设置信号量sem0管理s1,信号量sem1管理s2,用P、V操作实现互斥。阻塞操作负责完成执行进程从执行态e到等待态w的转换,并插入相应等待队列;唤醒操作负责完成等待进程从等待态w到高就绪态r的转换。
32、这里没有设置就绪队列。(因为进程少,调度时通过遍历进程查找。)若干模块功能及流程图:main()函数功能: 调度进程并执行选中进程代码。直到所有进程均执行完毕。 主程序 Main()初始化init() 进程调度有当前执行进程?打印最后结果 N Y结束当前执行进程号 0 1 2 其他出错报告执行process3执行process1执行process2Scheduler()函数功能: 进程调度程序。首先选择进程,然后考察:如处理器空闲,则置选中进程为运行态e;如处理器不空闲,比较当前正在运行进程与选中进程优先级别,若选中进程优先级别较高,则置选中进程为执行态e,并将原运行进程置为高就绪态r,否则不
33、改变正在运行进程。 调度程序Scheduler()选择进程未选到进程且当前无执行进程?返回空 Y N选到进程? N Y当前处理器空?将选中进程置为运行态e Y N 选中进程优先级高于当前执行进程? N Y当前进程转入高就绪状态r,选中进程置为运行态e(成为当前进程)。恢复运行态进程现场返回当前执行进程号 Process1() 进程0执行代码当前程序地址 其他register1=1 a b cregisteri<6? d N 退出程序rgisteri=rgisteri+1 e f YRgisteri<6?申请信号量sem0成功? N Y N Y a1:进程时间片到? Y Y结束进程
34、N b1: s1=s1+1 释放信号量sem0。有等待此信号量进程?返回 Y Nc1:申请信号量sem1成功? N Yd1:检查进程时间片到? N Y Ne1: s2=s2+1 释放信号量sem1。有等待此信号量进程? Y Nf1:打印进程循环计算次数 Process1()在执行的一开始,首先判断当前执行位置。该位置应该是上次中断的下一条指令,以便继续程序执行。每次程序被中断时,都在对应进程现场保留区savearea1保存这个中断地址。当这个进程被再次调度执行时,调度程序就会恢复现场,包含把这个中断地址恢复到addr (执行程序的当前指令地址),程序转入这条指令,继续程序的执行。程序在执行过程
35、中,经常被时间片中断程序中断,检查时间片是否到限。如果到限,必须退出本次执行,重新执行调度程序。退出之时,必须保存该程序的执行现场。(目前执行现场只有寄存器内容、中断地址)程序在执行过程中,如果需要访问s1、s2变量,必须遵循先申请(P操作)、后使用、最后释放(V操作)的顺序。 时间片中断 timeint()生成随机数XX<0.33且当前执行进程为进程0? Y 进程0时间片未到 N0.33X<0.66且当前执行进程为进程1? Y 进程1时间片未到 N0.66X<1且当前执行进程为进程2? Y 进程2时间片未到 N当前执行进程时间片到:将当前执行进程置为低就绪状态t,释放处理器
36、。返回FALSE(时间片未到)返回TRUE(时间片到) P操作信号量semse的值减1信号量semse的值>=0? Y 成功申请 N 信号量申请失败处理:阻塞当前进程,保存当前进程现场,释放处理器。返回false(申请成功)返回true(失败) V 操作信号量semse的值加1信号量semse的值>0? Y 无等待进程 N 有等待进程有等待进程处理:唤醒等待进程,保存当前进程现场。返回TRUE(有等待进程)返回FALSE(无等待进程)代码:#include <stdio.h>#define TRUE 1#define FALSE 0#define MAXPRI 100#
37、define NIL -1/进程控制块struct int id; /进程号 char status; /进程状态,'e'-执行态 'r'-高就绪态 't'-低就绪态 'w'-等待态 'c'-完成态 int nextwr; /等待链指针,指示在同一信号量上等待的下一个等待进程的进程号。 int priority; /进程优先数,值越小,优先级越高。pcb3;/共3个进程/s1、s2为三个进程共享的变量;seed为随机值;registeri模拟寄存器值,存放计算的重复次数。int registeri,s1,s2,se
38、ed,exe=NIL;/exe为当前运行(占有cpu)的进程号/2个信号量sem0、sem1,分别与共享变量s1、s2相联系。/对应信号量sem0、sem1分别有两个阻塞队列,队列首由sem.firstwr指定,队列链指针是pcb.nextwrstruct int value;/信号量值 int firstwr;/等待该信号量的阻塞队列的首个进程号sem2;/三个进程的现场保留区,其中savearea0为寄存器内容,savearea1为下一条指令地址。char savearea34;char addr;/当前执行程序的当前指针void main();void init();float rand
39、om();int timeint(char ad);int scheduler();int find();int p(int se,char ad);void block(int se);int v(int se,char ad);void wakeup(int se);void process1();void process2();void process3();void eexit(int n);/-/主程序void main() int currentProcess; printf("进程管理器n"); init(); printf("s1=%d,s2=%d
40、n",s1,s2); printf("进程1、进程2、进程3已经准备好!n"); for (;) currentProcess=scheduler(); /进程调度,选择优先级别最高的就绪进程运行。if (currentProcess=NIL) break; /所有进程已经运行完毕,结束。switch (currentProcess) /运行当前进程代码 case 0: process1(); break; case 1: process2(); break; case 2: process3(); break; default: printf("进程号
41、出错!n"); break; printf("最后结果:s1=%d,s2=%dn",s1,s2);/-/初始化void init() int i,j; s1=0;s2=0; /生成进程控制块 for (j=0;j<3;j+) pcbj.id=j; /进程号 pcbj.status='r' /进程初始状态为高就绪状态 pcbj.nextwr=NIL; printf("n进程 %d 的优先数?",j+1); scanf("%d",&i); pcbj.priority=i; /进程优先级 /初始化两个
42、信号量 sem0.value=1;/与s1相联系 sem0.firstwr=NIL; sem1.value=1;/与s2相联系 sem1.firstwr=NIL; /初始化现场保留区。每个进程均有现场保留区。 for (i=0;i<3;i+) for (j=0;j<4;j+)saveareaij='0' /end of init()/-/生成01之间随机值float random() int m; if (seed<0) m=-seed; else m=seed; seed=(25173*seed+13849)%65536; return (m/32767.0);/-/检测当前进程的时间片是否已到。未到,返回FALSE,否则返回TRUE。系统采用分时执行,/规定每个进程的执行概率为33%,用产生数x模拟时间片。/ad为程序的当前语句地址。int timeint(char ad) float x; x=random(); if (x<0.33)&&(exe=0) return (FALSE);/当前进程为进程1,时间片未到。 if (x>=0.33)&
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 驾驶员职业安全与权益保障劳动合同
- 美团点评团购服务合同纠纷解决及赔偿标准
- 教育机构聘请兼职外教进行英语语法与词汇教学合同
- 2025年凤尾蕨科行业研究报告及未来行业发展趋势预测
- 香港地区高层管理人员保密协议及竞业禁止合同
- 大数据图像处理框架研究-洞察及研究
- 天冬与抗抑郁药相互作用探索-洞察及研究
- 2025年电感元件行业研究报告及未来行业发展趋势预测
- 大数据驱动的能源预测-洞察及研究
- 基于AI的社区分析与规划-洞察及研究
- 2025浙教版(2024)八年级上册科学教学计划(三篇)
- 儿童抽动障碍的诊断与评估(2025年)解读课件
- 发热护理课件
- 2025年行政许可法知识竞赛题库及答案
- 库房管理基础知识培训课件
- 1.2《我们都是社会的一员》教学设计 2025-2026学年统编版道德与法治八年级上册
- 2024年劳动争议调解仲裁法知识竞赛题库与答案
- 劳动与技术小学开学第一课
- 新诊断心房颤动的护理查房
- 生产策划管理办法
- 《无人机基础概论》无人机专业全套教学课件
评论
0/150
提交评论