版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、本科毕业设计(论文)开题报告学生姓名 学 号 指导教师 学院(系) 信息技术学院 专 业 计算机科学与技术 交稿日期 文献翻译注意:每个学生必须提交15000个以上印刷符号、与课题研究密切相关的外文文献的中文翻译文章。(可增页)这份论文介绍了用线程编写并发程序。线程可以允许编写多个程序同时执行,程序同步分享内存。这份论文描述了线程和并发的基础原理,然后对于每个原理的运用提供了指导。指导部分对于如何用最有效的使用每个部分提供了建议,并且给予什么将会导致错误的警告,同时告诉你如何躲避这些陷阱。这份论文致力于帮助那些有经验的程序员,帮助他们获得并发程序的经验。使用的程序语言是c#,但是大多数辅导练习
2、同样可以使用其他线程语言,像java.。 概述:设计,语言,运行 附加的关键字和短语:线程,并发,多重处理,同步1. 介绍 几乎每一个现代的操作系统或者程序开发环境都支持程序的并行处理。其中最流行的机制就是在一个单独地址空间里支持多重轻量级的“线程”,被一个单独的程序使用。 即使对于有经验的老程序员而言解释线程也是困难的,并发程序有顺序执行的程序所没有的技术和陷阱,其中许多技术是显著的,也有一些不明显的技术。甚至有一些陷阱初看上去还很顺眼(比方说,死锁是个令人愉悦的软缺陷-所有的迹象完整但你的程序会停止运行),但是这些会导致一些潜在的执行错误。 这份论文就是给你关于编写线程的程序介绍,并且对于
3、那些运行差的技术或交互给予警告。它应该可以提供足够的提示,帮助程序员去建立一个大量的多重线程程序-准确、有效、惊喜的执行。 这份论文是我原本在1989年出版的论文修订版,蕴含了我经过多年教授学生如何使用线程的经验。但是14年过去发生了很多改变,既有在程序设计方面也有在电脑硬件方面。我希望这个修订,既可以呈现早先论文本质上的同样想法,也使得它对于当代读者而言,更加容易理解更加有用。 线程是一个简单的概念:一个连续的控制流。在高级语言中你经常使用调用语句编写线程,调用语句按照传统的栈管理规则。通过一个单独的线程,至少有一个程序执行。程序员使用一个线程时候没有什么新的东西要理解。 在程序中使用多线程
4、意味着在每个瞬间有多个程序执行,每个都是属于它的线程。程序员可以观看大多数同时执行的线程,就像计算机被赋予多处理器去处理线程。程序员被要求决定什么时候和哪里去创建多线程,或者接受这样的决定实现库或者运行环境。除此之外,程序员必须偶尔意识到电脑或许不是真正的同时运行所有它的线程。 线程在同一个地址空间运行,意味着电脑硬件配置可以允许线程读和写同样的内存地址。在一个传统的高级语言中,这通常符合全局变量。这是被程序的所有线程分享,就像那些线程分享的实例变量,每一个线程在一个分开的调用栈执行。 c#有一个机制(在java也一样)对于静态域特别的线程将不被分享,但是我将在这篇论文上忽视这些功能。2.关于
5、程序中c#线程的介绍。 程序员有责任的使用同步机制,去确认共享的内存是否可以接入,并且可以给予正确的响应。线程总是被认为“轻量级”的。这意味线程创建,存在,摧毁和同步是足够方便的,以至程序员可以使用他们满足所有的并发需要。 请注意我是选择性向你介绍有特点的技术集合。因为一项详细的调查将太花费介绍-我将讨论那些最重要的线程基元,无视那些功能像-线程环境信息或者链接其他机制,像nt内核或则其他对象。因此本文中我展示的例子、问题、和解决方法,都是为了决定如何设计线程-可以在c#程序和他的支持系统中设计。这儿展示的技术来源于过去的25年中(从1978)我个人经验-我没有企图代表那些有不同意见同事关于哪
6、些技术是好或者重要。 我从未如此,我相信懂得这里展示的技术将获得并发线程健全的基础。 这份论文使用的的范例使用c#语言,这样熟悉现代语言的人将较容易懂得。包括java,java和c#相当程度上不同。我将指出这些不同。这些例子将倾向展示那些关于并发和同步的特点-不是尝试在真正的程序中使用这些例子。 线程不是一个自动化的线性多重工具,编译器为了多重处理将消耗一个明显的序列程序和产生对象编码。这是一项完全不同的技术,我不将在这儿讨论。2. 为什么使用并发? 如过生活没有使用并发将会简单很多。但是有很多因素强迫你使用。最明显的原因是为了多处理。通过这些机器,同时发生的很多处理,线程将是一项可以充分利用
7、硬件的工具。使用线程这个选择,在大多数传统的操作系统上,可以配置你的程序分开运行在分开的地址空间。这原本倾向使用昂贵的设置,并且消耗较高的地址空间,甚至在分享片段之间会有压力。通过使用一个轻量级的多线程工具,程序员可以很轻巧的完成这些工作。这看上去,系统中有10个完美工作的并行处理器将胜过1000个处理器。 clr(通用语言运行) 通过c#应用介绍给多余的“应用领域”内容,允许多重程序去运行在一个单独硬件地址空间,但那不影响你的程序使用线程。 线程第二个大展身手的领域是在运行慢的工具,像硬盘,网络,终端,打印机。这些案例中,一个高效的程序将用完成一些有效的工作,而不是等待工具处理它的下个工作(
8、比方说完成一个硬盘从网络发送或接收一个包)就像我们接下来将看到的,如果你认为请求都是按序列的,这将很简单得通过线程编写。它们会停止调用线程直到要求完成),那个程序同时在其他线程中做其他的工作。尤其是应用于更高层的较慢的请求,例如用一个网络服务器运行一个远程调用。 第三个并发来源是使用者。当你的程序运行一些对于使用者而言很长的任务,程序应该仍然有响应:窗口应该重新绘制,滚动条将滚动他们的内容,当将点击取消按钮时时实现取消。线程是一像这样运行的便捷方式:从图形界面接收的长的任务可以运行在分开的线程,如果重新绘制一个复杂的画面将花很长时间,它也需要在一个分开的线程。在第六章,我将讨论一些实现这个任务
9、的技术。 最终并发源是当建造一个分布式系统时。现在我们经常鼓励分享网络服务器(像一个网站服务器,一个数据库,或者一个等待打印的客户端),服务器从多台客户端得到服务请求。用多重线程允许服务器并发处理客户的需求,而不是人工得连续处理它们(或者为每一个客户端以巨大的开销创建服务器) 有时候你可以故意的给你的程序添加并发,以减少操作的不安因素(在调用一个方法和返回方法之间的时间)通常,一些工作遭受方法调用可能会被延期,因为它不影响调用的结果。举例来说,当你在一个平衡树上添加或者减少一些东西,你可能很高兴在重新平衡树之前返回调用。通过线程你可以轻松完成这些目标:在一个分开的线程重新平衡。如果分开的线程是
10、按照较低的优先级安排,接下来的工作可以当你不较忙的时候完成(举例说,当等待用户的输入)为了延期工作而添加线程是一个强有力的技术,甚至在一个单一处理器。甚至如果全部的工作完成了,它可以减少不安因素,可以提高的你的程序可靠性和使用者的愉悦感。3. 线程的设计在我们对于多线程的基本类型取得一致意见之前讨论编写线程是没有意义的。不同的系统支持的线程都提供相似的功能,但有很多细节差异。通常来说有四个主要机制:线程创建,互斥现象,等待事件,和一些为了离开长期等待的线程协议。他们都基于c#线程工具:“system.threading命名空间和“lock”语句。 当你看到“system.threading”命
11、名空间,你将面对的选择范围感到气馁:是monitor或mutex,wait或autoresetecent,interrupt或abort?幸运的是有一个简单的答案:使用lock语句,monitor类和inrerrupt方法。那些是将来我将使用在剩下的论文中使用的功能。现在,你将忽略剩下的system.threading,尽管我将为你在第9章略述。3.1线程的创建 在c#你通过一个对象类型“type”创建一个线程,给予它构造一个”threadstart“委托,并且调用新线程start方法。新线程通过调用委托方法执行并发。当方法返回,线程结束。你可以调用“join”线程方法:这会调用线程直到给予其
12、结束。创建或者开始一个线程通常被叫做“forking”。 举例说,接下来的程序片段并发调用执行方法“foo.a()”和”foo.b()”,并且只有当两个方法调用完成时候算执行完毕。当然,方法“a”或许连接区域“foo。thread t = new thread(new threadstart(foo.a); t.start(); foo.b(); t.join(); 在练习中,你或许不经常使用“join”,大多数叉状线程是永久性线程,或者没有结果,或者通过一些同步协议传达结果而不是“join”。分叉线程很好,但是从不有相应调用“join”。3.2 互斥现象 最简单的线程交互方法是分享内存,在一
13、个面向对象的语言中,这通常表达为连接不同类的静态域,或者分享对象的实例。由于线程并列运行,程序员必须明确的避免错误出现,当超过一个线程连接分享的变量。做这个工作的最简单的工具就是一个基元提供交互的处理(有时候决定性的部分),为一个任何时间都可以执行的特定的区域线程代码详细说明。在c#设计中,只用“monitor”类和“lock”语句完成。 c#“delegate语句只是一个来自一个对象和它的方法的构造对象。在java中,你将明确定义举例说明一个类。 “lock”语句的自变量可以成为任何对象:在c#每个对象实现互斥锁定。在任何时刻,一个对象可以是“locked”或者“unlocked”,初始化解
14、锁。“lock”语句锁定给定的对象,接下来执行包含的语句,接下来解锁对象。在“lock”语句中执行的线程被称作“hold”,给予对象的锁定。若果其他的线程试图锁定已经锁定的对象,第二个线程块会(询问对象的锁定)直到对象解锁。 通常使用“lock”语句是为了保护对象的实例域,通过锁死对象无论程序何时连接。举例说,接下俩的程序片段一次只能处理一个线程,可以用“setkv”方法执行赋值语句。class kv string k, v; public void setkv(string nk, string nv) lock (this) this.k = nk; this.v = nv; 然而,有其他
15、的模式给予选定的对象锁定保护变量,通常来说,你完成一系列变量互斥,通过结合它们给定的对象,接下来些你编写程序只有当它连接那些保持锁定线程的变量(举例,从一个“lock”语句的线程处理锁定对象)这是监视器的基础概念,首先由rony hoare描述。 c#语言和它运行期不限制你选择哪一个对象锁定,但是足够明智的话你将选择最明显的。当变量是变量的实例,对象明显可以锁死(作为“setkv”方法,)。当变量是一个类的静态域,一个方便的对象由c#运行期间展示类的类型。举例来说,接下来的片断中。“kv”的静态域“head”是被对象“typeof(kv)”保护。在“addtolist”方法中的“lock”语句
16、提供互斥为了添加一个“kv”对象给连接的表。表头是“head”:一个线程执行使用一次“head”的语句。 在这些代码中实例“next”也通过”typeof(kv)“保护static kv head = null; kv next = null; public void addtolist() lock (typeof(kv) system.diagnostics.debug.assert(this.next = null); this.next = head; head = this; 3.3 等待条件 你可以把一个对象的锁定视为一个简单的资源的日程机制。在“lock”语句中的资源日程管理是分
17、享内存连接,并且日程的一次计划使用一个线程,但是,经常程序员需要展示更多复杂的日程计划。这需要使用一个机制可以允许一个线程无效直到一些条件成立。在java线程系统。这个机制通常叫做”条件变量“和符合分开的分配对象。在java和c#对于这个机制有独自的类型。代替每一个对象固有的实现条件变量,并且“monitor”类提供静态的“wait”,“pulse”和“pulseall”方法去操作一个对象的条件变量。 一个线程调用“wait”必须已经保持对象的锁定(否则调用“awit”将抛出错误)。“wait”操作将解锁对象和无效化线程。一个线程用这种方法无效化被称作“等待对象”。“pulse”方法不做任何事
18、,直到至少有一个线程等待这个想成(或许超过一个),“pulseall”方法很像“pulse”方法除了唤醒对象所有的等待线程。当一个线程在“wait”无效化之后唤醒,它仍然锁定对象,并且返回。注意对象的锁定可能不会立即完成,在新唤醒的线程例子中会一直无效化直到可以锁定。 如果有一个线程调用“wait“当它已经多次取得对象的锁定,”wait”方法释放(并且接下来重新询问)锁定次数。 这是很重要的,去意识到新的唤醒线程可能不是下一个锁定的线程:一些其他的线程可能会干涉。这意味着变量由锁定导致的保护状态,可能在你调用“pulse“和线程从”wait返回之前改变。我将在第5章讨论这个结论。 在java系
19、统之前,“wait”过程或者方法由两个争论:一个锁定和一个条件变量,在java和c#中,这结合成一个单独的争论,同时的锁定和等待队列。就更早的系统而言,这意味着“monitor”类每个锁定只支持一个类。 对象的锁定计划保护被分享的数据。如果一些线程a需要资源,它锁定合适对象和测试分享的数据。如果资源可以得到,线程继续。如果不能,它解锁对象并且无效化它,通过调用“wait“。接下来,当一些其他的线程b使资源可得唤醒线程a通过调用“pulse”或者“pulse all”。举例,我们可以添加下列“getfrolist”方法给类”kv“。这个方法会一直等待直到连接的表非空,并且移去表的首项。publi
20、c static kv getfromlist() kv res; lock (typeof(kv) while (head = null) monitor.wait(typeof(kv); res = head; head = res.next; res.next = null; / for cleanliness return res; 并且接下来对于“添加到表“方法相反的方法,可能被一个线程使用去添加一个对象到“head”并且唤醒一个等待它的线程。public void addtolist() lock (typeof(kv) /* were assuming this.next = n
21、ull */ this.next = head; head = this; monitor.pulse(typeof(kv); 3.4线程的中断 线程工具的最后我将讨论部分,是一个为了中断一个特定的线程的机制,它由一个长时间的等待引起。在c#运行期间这由线程的“interrupt”方法提供。如果一个线程“t“是无效化的并且等待一个对象(举例,它无效化在调用“monitor.wait”),另一个线程调用“errupt()”,接着”t“将恢复执行再一次锁死对象(如果需要,等待锁死解锁了)接着抛出“threadinterruptedexception”.(如果线程调用“thread.sle
22、ep”或者”t.join”一样)可以选择,如果“t”不在等待在一个对象(并且他不在睡眠或者等待在”t.join“),接下面临“interrupt”已经被调用会记录并且线程将抛出“threadinterruptedexception”下一次将等待或者睡眠。 举例来说,考虑到线程“t”已经调用kv的“getfrromlist”的方法,并且在连接表上无效化等待kv的对象。它看上去吸引人,如果一些其他的线程不决定”getfromlist”调用(举例子,用户用鼠标点击取消键),接下来“t”将从“getfromlist“返回。如果线程处理取消要求,发生知道对象在“t”在等待,接下俩它将设置一个标志并且调用
23、“monitor.pulse”给对象。然而,更多的实际调用“monitor.wait“。完成无形线程就是处理取消要求。按这个情形,线程处理取消需求通过调用“errupt()”可能完成它的目标。当然,一些其他调用“t”将有处理“threadinterruptexception”尤其是你对意外做什么依靠设计,举例来说,我们就安排一个中断的调用从“getfromlist”返回空值。public static kv getfromlist() kv res = null; try lock (typeof(kv) while (head = null) monitor.wait(typeof
24、(kv); res = head; head = head.next; res.next = null; catch (threadinterruptedexception) return res; 中断是复杂的,并且使用产品复杂的程序。我们将讨论他们在第七章更多的细节.注意:请将外文文献原文复印件附在后面。an introduction to programming with c# threads andrew d. birrell this paper provides an introduction to writing concurrent programs with “threads
25、”. a threads facility allows you to write programs with multiple simultaneous points of execution, synchronizing through shared memory. the paper describes the basic thread and synchronization primitives, then for each primitive provides a tutorial on how to use it. the tutorial sections provide adv
26、ice on the best ways to use the primitives, give warnings about what can go wrong and offer hints about how to avoid these pitfalls. the paper is aimed at experienced programmers who want to acquire practical expertise in writing concurrent programs. the programming language used is c#, but most of
27、the tutorial applies equally well to other languages with thread support, such as java.categories and subject descriptors: d.1.3 programming techniques: concurrent programming; d.3.3 programming languages: language constructs and featuresconcurrent programming structures; d.4.1 operating systems: pr
28、ocess management general terms: design, languages, performanceadditional key words and phrases: threads, concurrency, multi-processing, synchronization permission to copy in whole or part without payment of fee is granted for non-profit educational and research purposes provided that all such whole
29、or partial copies include the following: a notice that such copying is by permission of microsoft corporation; an acknowledgement of the author of the work; and this copyright notice. parts of this work are based on research report #35 published in 1989 by the systems research center of digital equi
30、pment corporation and copyright by them. that material is used here by kind permission of hewlett-packard company. all rights reserved. an introduction to programming with c# threads . 1 1. introduction almost every modern operating system or programming environment provides support for concurrent p
31、rogramming. the most popular mechanism for this is some provision for allowing multiple lightweight “threads” within a single address space, used from within a single programprogramming with threads introduces new difficulties even for experienced programmers. concurrent programming has techniques a
32、nd pitfalls that do not occur in sequential programming. many of the techniques are obvious, but some are obvious only with hindsight. some of the pitfalls are comfortable (for example, deadlock is a pleasant sort of bugyour program stops with all the evidence intact), but some take the form of insi
33、dious performance penalties. the purpose of this paper is to give you an introduction to the programming techniques that work well with threads, and to warn you about techniques or interactions that work out badly. it should provide the experienced sequential programmer with enough hints to be able
34、to build a substantial multi-threaded program that workscorrectly, efficiently, and with a minimum of surprises. this paper is a revision of one that i originally published in 1989 2. over the years that paper has been used extensively in teaching students how to program with threads. but a lot has
35、changed in 14 years, both in language design and in computer hardware design. i hope this revision, while presenting essentially the same ideas as the earlier paper, will make them more accessible and more useful to a contemporary audience. a “thread” is a straightforward concept: a single sequentia
36、l flow of control. in a high-level language you normally program a thread using procedure calls or method calls, where the calls follow the traditional stack discipline. within a single thread, there is at any instant a single point of execution. the programmer need learn nothing new to use a single
37、 thread. having “multiple threads” in a program means that at any instant the program has multiple points of execution, one in each of its threads. the programmer can mostly view the threads as executing simultaneously, as if the computer were endowed with as many processors as there are threads. th
38、e programmer is required to decide when and where to create multiple threads, or to accept such decisions made for him by implementers of existing library packages or runtime systems. additionally, the programmer must occasionally be aware that the computer might not in fact execute all his threads
39、simultaneously. having the threads execute within a “single address space” means that the computers addressing hardware is configured so as to permit the threads to read and write the same memory locations. in a traditional high-level language, this usually corresponds to the fact that the off-stack
40、 (global) variables are shared among all the threads of the program. in an object-oriented language such as c# or java, the static variables of a class are shared among all the threads, as are the instance variables of any objects that the threads share.* each thread executes on a separate call stac
41、k with its own separate local variables. the programmer is* there is a mechanism in c# (and in java) for making static fields thread-specific and not shared, but im going to ignore that feature in this paper. 2 . an introduction to programming with c# threads responsible for using the synchronizatio
42、n mechanisms of the thread facility to ensure that the shared memory is accessed in a manner that will give the correct answer.* thread facilities are always advertised as being “lightweight”. this means that thread creation, existence, destruction and synchronization primitives are cheap enough tha
43、t the programmer will use them for all his concurrency needs. please be aware that i am presenting you with a selective, biased and idiosyncratic collection of techniques. selective, because an exhaustive survey would be too exhausting to serve as an introductioni will be discussing only the most im
44、portant thread primitives, omitting features such as per-thread context information or access to other mechanisms such as nt kernel mutexes or events. biased, because i present examples, problems and solutions in the context of one particular set of choices of how to design a threads facilitythe cho
45、ices made in the c# programming language and its supporting runtime system. idiosyncratic, because the techniques presented here derive from my personal experience of programming with threads over the last twenty five years (since 1978)i have not attempted to represent colleagues who might have diff
46、erent opinions about which programming techniques are “good” or “important”. nevertheless, i believe that an understanding of the ideas presented here will serve as a sound basis for programming with concurrent threads. throughout the paper i use examples written in c# 12. these should be readily un
47、derstandable by anyone familiar with modern object-oriented languages, including java 7. where java differs significantly from c#, i try to point this out. the examples are intended to illustrate points about concurrency and synchronizationdont try to use these actual algorithms in real programs. th
48、reads are not a tool for automatic parallel decomposition, where a compiler will take a visibly sequential program and generate object code to utilize multiple processors. that is an entirely different art, not one that i will discuss here. 2. why use concurrency? life would be simpler if you didnt
49、need to use concurrency. but there are a variety of forces pushing towards its use. the most obvious is the use of multi-processors. with these machines, there really are multiple simultaneous points of execution, and threads are an attractive tool for allowing a program to take advantage of the ava
50、ilable hardware. the alternative, with most conventional operating systems, is to configure your program as multiple separate processes, running in separate address spaces. this tends to be expensive to set up, and the costs of communicating between address spaces are often high, even in the presenc
51、e of shared segments. by using a lightweight multi-threading facility, the programmer can utilize the processors cheaply. this seems to work well in systems having up to about 10 processors, rather than 1000 processors. * the clr (common language runtime) used by c# applications introduces the addit
52、ional concept of “application domain”, allowing multiple programs to execute in a single hardware address space, but that doesnt affect how your program uses threads. an introduction to programming with c# threads . 3 a second area where threads are useful is in driving slow devices such as disks, n
53、etworks, terminals and printers. in these cases an efficient program should be doing some other useful work while waiting for the device to produce its next event (such as the completion of a disk transfer or the receipt of a packet from the network). as we will see later, this can be programmed qui
54、te easily with threads by adopting an attitude that device requests are all sequential (i.e., they suspend execution of the invoking thread until the request completes), and that the program meanwhile does other work in other threads. exactly the same remarks apply to higher level slow requests, suc
55、h as performing an rpc call to a network server. a third source of concurrency is human users. when your program is performing some lengthy task for the user, the program should still be responsive: exposed windows should repaint, scroll bars should scroll their contents, and cancel buttons should c
56、lick and implement the cancellation. threads are a convenient way of programming this: the lengthy task executes in a thread thats separate from the thread processing incoming gui events; if repainting a complex drawing will take a long time, it will need to be in a separate thread too. in a section
57、 6, i discuss some techniques for implementing this. a final source of concurrency appears when building a distributed system. here we frequently encounter shared network servers (such as a web server, a database, or a spooling print server), where the server is willing to service requests from mult
58、iple clients. use of multiple threads allows the server to handle clients requests in parallel, instead of artificially serializing them (or creating one server process per client, at great expense). sometimes you can deliberately add concurrency to your program in order to reduce the latency of operations (the elapsed time between calling a method and the method ret
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 一年级数学计算题专项练习1000题集锦
- 三年级数学计算题专项练习汇编及答案
- 《全身体检》课件
- 人教九年级语文上册《写作 尝试创作》教学课件
- 2021年校园宿舍文化节的策划文案设计5篇
- 18.4-焦耳定律-人教版九年级物理全一册教学设计
- 初中教师家访心得体会13篇
- 轻化工安全分享
- 黄帝内经大全
- 劳动合同续签申请函
- 医疗安全不良事件警示教育
- 《意外险险种培训》课件
- 中小学生网络安全教育知识讲座
- 《民族区域自治制度》课件
- 电吹管简易指法
- 淹溺的救治课件
- 工程公司QC小组提高水泥发泡式地暖地面隔热层一次施工合格率成果汇报
- 泌尿外科工作总结及计划
- 危险性较大的专项施工方案审批表
- 2023年数学竞赛AMC8试卷(含答案)
- 1 场景歌 教学课件
评论
0/150
提交评论