版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、<p><b> (</b></p><p> Process Management</p><p> The process is one of the fundamental abstractions in Unix operating systems. A process is a program(object code stored on so
2、me media) in execution. Processes are, however, more than just the executingprogram code (often called the text section in Unix). They also include a set of resources such as open files and pending signals, internal kern
3、el data, processor state, an address space, one or more threads ofexecution, and a data section containing global variables. Processes, in effect, are the </p><p> Threads of execution, often shortened to t
4、hreads, are the objects of activity within the process. Each thread includes a unique program counter, process stack, and set of processor registers. The kernel schedules individual threads, not processes. In traditional
5、 Unix systems, each process consists of one thread. In modern systems, however, multithreaded programsthose that consist of more than one threadare common. Linux has a unique implementation of threads: It does not differ
6、entiate between th</p><p> On modern operating systems, processes provide two virtualizations: a virtualized processor and virtual memory. The virtual processor gives the process the illusion that it alone
7、monopolizes the system, despite possibly sharing the processor among dozens of other processes. discusses this virtualization. Virtual memory lets the process allocate and manage memory as if it alone owned all the memor
8、y in the system. Interestingly, note that threads share the virtual memory abstraction while each rec</p><p> A program itself is not a process; a process is an active program and related resources. Indeed,
9、 two or more processes can exist that are executing the same program. In fact, two or more processes can exist that share various resources, such as open files or an address space.</p><p> A process begins
10、its life when, not surprisingly, it is created. In Linux, this occurs by means of the fork()system call, which creates a new process by duplicating an existing one. The process that calls fork() is the parent, whereas th
11、e new process is the child. The parent resumes execution and the child starts execution at the same place, where the call returns. The fork() system call returns from the kernel twice:once in the parent process and again
12、 in the newborn child.</p><p> Often, immediately after a fork it is desirable to execute a new, different, program. The exec*() family of function calls is used to create a new address space and load a new
13、 program into it. In modern Linux kernels, fork() is actually implemented via the clone() system call, which is discussed in a followingsection.</p><p> Finally, a program exits via the exit() system call.
14、This function terminates the process and frees all its resources. A parent process can inquire about the status of a terminated child via the wait4() system call, which enables a process to wait for the termination of a
15、 specific process. When a process exits, it is placed into a special zombie state that is used to represent terminated processes until the parent calls wait() or waitpid().</p><p> Another name for a proces
16、s is a task. The Linux kernel internally refers to processes as tasks. although when I say task I am generally referring to a process from the kernel's point of view.</p><p> 1 Process Descriptor and t
17、he Task Structure</p><p> The kernel stores the list of processes in a circular doubly linked list called the task list. Each element in the task list is a process descriptor of the type struct task_struct,
18、 which is defined in <linux/sched.h>.The process descriptor contains all the information about a specific process.</p><p> The task_struct is a relatively large data structure, at around 1.7 kilobyte
19、s on a 32-bit machine. This size,however, is quite small considering that the structure contains all the information that the kernel has and needs about a process. The process descriptor contains the data that describes
20、the executing programopen files, the process's address space, pending signals, the process's state, and much more</p><p> 2 Allocating the Process Descriptor</p><p> The task_struct s
21、tructure is allocated via the slab allocator to provide object reuse and cache coloring Prior to the 2.6 kernel series, struct task_struct was stored at the end of the kernel stack of each process. This allowed architec
22、tures with few registers, such as x86, to calculate the location of the process descriptor via the stack pointer without using an extra register to store the location. With the process descriptor now dynamically created
23、via the slab allocator, a new structure, st</p><p> The thread_info structure is defined on x86 in <asm/thread_info.h> as</p><p> struct thread_info {</p><p> struct task_s
24、truct *task;</p><p> struct exec_domain *exec_domain;</p><p> unsigned long flags;</p><p> unsigned long status;</p><p> __u32 cpu;</p><p> __s32 pree
25、mpt_count;</p><p> mm_segment_t addr_limit;</p><p> struct restart_block restart_block;</p><p> unsigned long previous_esp;</p><p> __u8 supervisor_stack[0];</p&
26、gt;<p><b> };</b></p><p> Each task's tHRead_info structure is allocated at the end of its stack. The task element of the structure is a pointer to the task's actual task_struct.
27、</p><p> 3 Storing the Process Descriptor</p><p> The system identifies processes by a unique process identification value or PID. The PID is a numerical value that is represented by the opa
28、que type pid_t, which is typically an int. Because of backward compatibility with earlier Unix and Linux versions, however, the default maximum value is only 32,768 although the value can optionally be increased to the f
29、ull range afforded the type. The kernel stores this value as pid inside each process descriptor.</p><p> This maximum value is important because it is essentially the maximum number of processes that may ex
30、ist concurrently on the system. Although 32,768 might be sufficient for a desktop system, large servers may require many more processes. The lower the value, the sooner the values will wrap around, destroying the useful
31、notion that higher values indicate later run processes than lower values. If the system is willing to break compatibility with old applications, the administrator may increase the</p><p> Inside the kernel,
32、 tasks are typically referenced directly by a pointer to their task_struct structure. In fact, most kernel code that deals with processes works directly with struct task_struct. Consequently, it is very useful to be able
33、 to quickly look up the process descriptor of the currently executing task, which is done via the current macro. This macro must be separately implemented by each architecture. Some architectures save a pointer to the ta
34、sk_struct structure of the currently runni</p><p> On x86, current is calculated by masking out the 13 least significant bits of the stack pointer to obtain the thread_info structure. This is done by the cu
35、rrent_thread_info() function. The assembly is shown here:</p><p> movl $-8192, %eax</p><p> andl %esp, %eax</p><p> This assumes that the stack size is 8KB. When 4KB stacks are e
36、nabled, 4096 is used in lieu of 8192.</p><p> Finally, current dereferences the task member of thread_info to return the task_struct:current_thread_info()->task; Contrast this approach with that taken by
37、 PowerPC (IBM's modern RISC-based microprocessor), which stores the current task_struct in a register. Thus, current on PPC merely returns the value stored in the register r2. PPC can take this approach because, unli
38、ke x86, it has plenty of registers. Because accessing the process descriptor is a common and important job, the PPC kernel deve</p><p> 4 Process State</p><p> The state field of the process
39、descriptor describes the current condition of the process. Each process on the system is in exactly one of five different states. This value is represented by one of five flags:</p><p> (1) TASK_RUNNING The
40、 process is runnable; it is either currently running or on a runqueue waiting to run. This is the only possible state for a process executing in user-space; it can also apply to a process in kernel-space that is actively
41、 running.</p><p> (2) TASK_INTERRUPTIBLE. The process is sleeping (that is, it is blocked), waiting for some condition to exist. When this condition exists, the kernel sets the process's state to TASK_R
42、UNNING. The process also awakes prematurely and becomes runnable if it receives a signal.</p><p> (3) TASK_UNINTERRUPTIBLE This state is identical to TASK_INTERRUPTIBLE except that it does not wake up and
43、become runnable if it receives a signal. This is used in situations where the process must wait without interruption or when the event is expected to occur quite quickly. Because the task does not respond to signals in t
44、his state, this state is less often used than TASK_INTERRUPTIBLE</p><p> (4)TASK_ZOMBIE The task has terminated, but its parent has not yet issued a wait4() system call. The task's process descriptor mu
45、st remain in case the parent wants to access it. If the parent calls wait4(), the process descriptor is deallocated.</p><p> (5) TASK_STOPPED Process execution has stopped; the task is not running nor is it
46、 eligible to run. This occurs if the task receives the SIGSTOP, SIGTSTP, SIGTTIN, or SIGTTOU signal or if it receives any signal while it is being debugged.</p><p> 5 Manipulating the Current Process State
47、</p><p> Kernel code often needs to change a process's state. The preferred mechanism is using set_task_state(task, state); This function sets the given task to the given state. If applicable, it also p
48、rovides a memory barrier to force ordering on other processors (this is only needed on SMP systems). Otherwise, it is equivalent to task->state = state; The method set_current_state(state) is synonymous to set_task_st
49、ate(current, state).</p><p> 6 Process Context</p><p> One of the most important parts of a process is the executing program code. This code is read in from an executable file and executed wi
50、thin the program's address space. Normal program execution occurs in userspace. When a program executes a system call or triggers an exception, it enters kernel-space. At this point, the kernel is said to be "ex
51、ecuting on behalf of the process" and is in process context. When in process context, the current macro is valid. Upon exiting the kernel, the process re</p><p> System calls and exception handlers are
52、 well-defined interfaces into the kernel. A process can begin executing in kernel.</p><p><b> 進(jìn)程管理</b></p><p> 進(jìn)程是Uinx操作系統(tǒng)最基本的抽象之一。一個(gè)進(jìn)程就是處于執(zhí)行期間的程序(目標(biāo)代碼放在某種存儲(chǔ)介質(zhì)上)。但進(jìn)程并不僅僅局限于一段可執(zhí)行程序(
53、Unix稱其為代碼段(text section))。通常進(jìn)程還要包含其他資源,像打開的文件、掛起的信號(hào)、內(nèi)核內(nèi)部數(shù)據(jù)、處理器狀態(tài)、地址空間及一個(gè)或多個(gè)執(zhí)行線程、當(dāng)然還包括用來(lái)存放全局變量的數(shù)據(jù)段等。實(shí)際上,進(jìn)程就是正在執(zhí)行的程序代碼的活標(biāo)本。</p><p> 執(zhí)行線程,簡(jiǎn)稱線程(thread),是在進(jìn)程中活動(dòng)的對(duì)象。每個(gè)線程用由一個(gè)獨(dú)立的程序計(jì)數(shù)器、進(jìn)程棧和一組進(jìn)程寄存器。內(nèi)核調(diào)度的對(duì)象是線程,而不是進(jìn)程。在
54、傳統(tǒng)的Unix系統(tǒng)中,一個(gè)進(jìn)程只包含一個(gè)線程,但現(xiàn)在的系統(tǒng)中,包含多個(gè)線程的多線程程序司空見慣。Linux系統(tǒng)的線程實(shí)現(xiàn)非常特別—他對(duì)線程和進(jìn)程并不特別區(qū)分。對(duì)Linux而言,線程只不過(guò)是一種特殊的進(jìn)程罷了。</p><p> 在現(xiàn)代操作系統(tǒng)中,進(jìn)程提供兩種虛擬機(jī)制:虛擬處理器和虛擬內(nèi)存。雖然實(shí)際上可能是許多進(jìn)程正在分享一個(gè)處理器,但虛擬處理器給進(jìn)程一種假象,讓這些進(jìn)程覺(jué)得自己在獨(dú)享處理器。而虛擬內(nèi)存讓進(jìn)程在獲
55、取和使用內(nèi)存是覺(jué)得自己擁有整個(gè)操作系統(tǒng)的所有內(nèi)存資源。有趣的是,注意在線程之間(這里是指包含在同一個(gè)進(jìn)程中的進(jìn)程)可以共享虛擬內(nèi)存,但擁有各自的虛擬處理器。</p><p> 程序本身并不是進(jìn)程:進(jìn)程是處于執(zhí)行期間的程序以及它所包含的資源的總稱。實(shí)際上完全可以存在兩個(gè)或者多個(gè)不同的進(jìn)程執(zhí)行的是同一個(gè)程序。并且兩個(gè)或兩個(gè)以上并存的進(jìn)程還可以共享許多諸如打開的文件、地址空間之類的資源。無(wú)疑,進(jìn)程在它被創(chuàng)建的時(shí)刻開始
56、存活。在Linux系統(tǒng)中,這通常是調(diào)用fork()系統(tǒng)調(diào)用的結(jié)果,該系統(tǒng)調(diào)用通過(guò)復(fù)制一個(gè)現(xiàn)有進(jìn)程來(lái)創(chuàng)建一個(gè)全新的進(jìn)程。調(diào)用fork()的進(jìn)程被稱為父子進(jìn)程,新產(chǎn)生的進(jìn)程被稱為子進(jìn)程。在調(diào)用結(jié)束的時(shí),在返回這個(gè)相同位置上,父進(jìn)程恢復(fù)執(zhí)行,子進(jìn)程開始執(zhí)行。Fork()系統(tǒng)調(diào)用從內(nèi)核返回兩次:一次回到父進(jìn)程,另一個(gè)回到新誕生的子進(jìn)程。</p><p> 通常,創(chuàng)建新的進(jìn)程都是為了立即執(zhí)行新的、不同的程序,而接著調(diào)用e
57、xec()這族函數(shù)就可以創(chuàng)建新的地址空間,并把新的程序載入。在現(xiàn)代Linux內(nèi)核中,fork()實(shí)際上是由clone()系統(tǒng)調(diào)用實(shí)現(xiàn)的,后者將在后面討論。</p><p> 最終,程序通過(guò)exit()系統(tǒng)調(diào)用退出。這個(gè)函數(shù)會(huì)終結(jié)進(jìn)程并將其占有的資源釋放掉。父進(jìn)程可以通過(guò)wait()系統(tǒng)調(diào)用查詢子進(jìn)程是否終結(jié),這其實(shí)使得進(jìn)程擁有了等待指定進(jìn)程執(zhí)行完畢的能力。進(jìn)程退出執(zhí)行后被置為僵死狀態(tài),直到它的父進(jìn)程調(diào)用wait
58、()或waitpid()為止。</p><p> 進(jìn)程的另一個(gè)名字是任務(wù)(task)。Linux內(nèi)核通常把進(jìn)程也叫做任務(wù)。在這里所說(shuō)的任務(wù)是指從內(nèi)核觀點(diǎn)看到的進(jìn)程。</p><p> 1 進(jìn)程描述符及任務(wù)結(jié)構(gòu)</p><p> 內(nèi)核把進(jìn)程存放在叫做任務(wù)隊(duì)列(task list)的雙向循環(huán)鏈表中。鏈表的每一項(xiàng)都是類型為task_struct、稱為進(jìn)程描述符的結(jié)構(gòu)
59、,改結(jié)構(gòu)定義在<linux/sched.h>文件中。進(jìn)程描述符中包含一個(gè)具體進(jìn)程的所有信息。</p><p> task_struct相對(duì)較大,在32位機(jī)器上,它大約有1.7k字節(jié)。但如果考慮到該結(jié)構(gòu)內(nèi)包含了內(nèi)核管理一個(gè)進(jìn)程所需要的所有信息,那么它的大小也相當(dāng)小了。進(jìn)程描述符中包含的數(shù)據(jù)能完整的描述一個(gè)正在執(zhí)行的程序:它打開的文件,進(jìn)程的地址空間,掛起的信號(hào),進(jìn)程的狀態(tài),還有其他更多的信息。<
60、/p><p><b> 2 進(jìn)程描述符</b></p><p> Linux通過(guò)slab非配器分配task_struct結(jié)構(gòu),這樣能達(dá)到對(duì)象復(fù)用和緩存著色的目的。在2.6以前的內(nèi)核中,各個(gè)進(jìn)程的task_struct存放在他們的內(nèi)核棧的尾端。這樣做的目的是為了讓那些像x86這樣寄存器較的硬件體系結(jié)構(gòu)只要通過(guò)棧指針就能算出它的位置,從而避免使用額外的寄存器專門記錄。由
61、于現(xiàn)在用slab分配器動(dòng)態(tài)生成task_struct,所以只需在棧底或棧頂創(chuàng)建一個(gè)新的結(jié)構(gòu)struct thread)info。這個(gè)新的結(jié)構(gòu)能使在匯編代碼中計(jì)算器偏移變得相當(dāng)?shù)娜菀住?lt;/p><p> 在x86上,thread_info {</p><p> Struct task_struct *任務(wù);</p><p> Struct exec_d
62、omain *exec_domain;</p><p> Unsigned long flags;</p><p> Unsigned long status;</p><p> __u32cpu;</p><p> __s32preempt_count;</p>&
63、lt;p> Mm_segment addr_limit;</p><p> Struct restart_blockrestart_block;</p><p> Unsigned longprevious_esp;</p><p> __u8supervisor_stack[0];</p>
64、<p><b> }</b></p><p> 每個(gè)任務(wù)的thread_info 結(jié)構(gòu)在它的內(nèi)核棧的尾端分配。結(jié)構(gòu)中task域中存放的是指向該任務(wù)實(shí)際task_struct的指針。</p><p> 3 進(jìn)程描述符的存放</p><p> 內(nèi)核通過(guò)一個(gè)唯一的進(jìn)程標(biāo)識(shí)值或PID來(lái)表示每個(gè)進(jìn)程。PID 是一個(gè)數(shù),表示為pid
65、_t隱含類型,實(shí)際上就是一個(gè)int類型。為了老版本的Unix和Linux兼容,PID 的最大值默認(rèn)設(shè)置為32768,盡管這個(gè)值也可以增加到類型所允許的范圍。內(nèi)核把每個(gè)進(jìn)程PID存放在他們各自的進(jìn)策劃那個(gè)描述符中。</p><p> 這個(gè)值很重要,因?yàn)樗鼘?shí)際上就是系統(tǒng)中允許同時(shí)存在的進(jìn)程的最大數(shù)目。盡管32768對(duì)一般的桌面系統(tǒng)足夠用了,但是大型服務(wù)器可能需要更新進(jìn)程。這個(gè)值越小,轉(zhuǎn)一圈就越快,本類數(shù)值大的進(jìn)程比
66、數(shù)值小的進(jìn)程遲運(yùn)行,但這樣一來(lái)就破壞了這一原則。如果確實(shí)需要的話,可以不考慮與老式系統(tǒng)的兼容,由系統(tǒng)管理員通過(guò)修改/proc/sys/kernel/pid_max來(lái)提高上限。</p><p> 在內(nèi)核中,訪問(wèn)任務(wù)通常需要獲得指向其task_struct指針。實(shí)際上,內(nèi)核中大部分處理進(jìn)程的代碼都是直接通過(guò)task_struct進(jìn)行的。因此,通過(guò)current宏查找到當(dāng)前正在運(yùn)行進(jìn)程的進(jìn)程描述符的速度就顯得尤為重要
67、。硬件體系結(jié)構(gòu)不同,該宏的實(shí)現(xiàn)也就不同,它必須針對(duì)專門的硬件體系結(jié)構(gòu)作處理。有的硬件體系結(jié)構(gòu)可以拿出一個(gè)專門寄存器來(lái)存放指向當(dāng)前進(jìn)程task_strcut的指針,用于加快訪問(wèn)速度。而有些像x86這樣的體系結(jié)構(gòu),就只能在內(nèi)核棧的尾端創(chuàng)建thread_info結(jié)構(gòu),通過(guò)計(jì)算偏移間接地查找task_struct結(jié)構(gòu)。</p><p> 在x86體系上,current把棧指針的后13個(gè)有效位屏蔽掉,用來(lái)計(jì)算出threa
68、d_info的偏移。該操作通過(guò)current_thread_info()函數(shù)完成的。匯編代碼如下:</p><p> Mov $-81925, %eax</p><p> Andl %esp, %eax</p><p> 這里假定棧的大小為8KB。當(dāng)4KB的棧啟用時(shí),就用4096,而不是8192。</p><p> 最后,cur
69、rent_thread_info()->task;</p><p> 對(duì)比一下這部分在PowerPC上的實(shí)現(xiàn)(IBM基于RISC的現(xiàn)代微處理器),我們可以發(fā)現(xiàn)當(dāng)前task_struct的地址是保存在一個(gè)寄存器中的。也就是說(shuō),在PPC上,current宏只需要把r2寄存器中的值返回就行了。與x86不一樣,PPC有足夠多的寄存器,所以它的實(shí)現(xiàn)有這樣的余地。而訪問(wèn)進(jìn)程描述符是一個(gè)重要的頻繁的操作,所以PPC的內(nèi)
70、核開發(fā)者會(huì)覺(jué)得完全有必要為此使用一個(gè)專門的寄存器。</p><p><b> 進(jìn)程狀態(tài)</b></p><p> 進(jìn)程描述符中的state域描述了進(jìn)程的當(dāng)前狀態(tài)。系統(tǒng)的每個(gè)進(jìn)程都必然處于五種進(jìn)程狀態(tài)的一種。該域的值也必為下列五種狀態(tài)標(biāo)志之一:</p><p> TASK_RUNNING(運(yùn)行)——進(jìn)程是可執(zhí)行的,它或者正在執(zhí)行,或者在運(yùn)行
71、隊(duì)列中等待執(zhí)行。這是進(jìn)程在用戶空間中執(zhí)行唯一可能的狀態(tài),也可以應(yīng)用到內(nèi)核空間中正在執(zhí)行的進(jìn)程。</p><p> TASK_INTERRUPTIBLE(可中斷)——進(jìn)程正在睡眠(也就是說(shuō)它被阻塞),等待某些條件的達(dá)成。一檔這些條件達(dá)成,內(nèi)核就會(huì)把進(jìn)程狀態(tài)設(shè)置為運(yùn)行。處于此狀態(tài)的進(jìn)程也會(huì)因?yàn)榻邮艿叫盘?hào)而提前被喚醒并投入到運(yùn)行。</p><p> TASK_UNINTERRUPTIBLE(
72、不可中斷)——除了不會(huì)因?yàn)榻邮艿叫盘?hào)而被喚醒從而投入運(yùn)行外,這個(gè)狀態(tài)與可打斷的狀態(tài)相同。這個(gè)狀態(tài)通常在進(jìn)程必須在等待時(shí)不受干擾或等待時(shí)間很快就會(huì)發(fā)生時(shí)出現(xiàn)。由于處于此狀態(tài)的任務(wù)對(duì)信號(hào)不做響應(yīng),所以較之可中斷狀態(tài),使用的較少。</p><p> TASK_ZOMBIE(僵死)——該進(jìn)程已經(jīng)結(jié)束了,但是其父進(jìn)程還沒(méi)有調(diào)用wait()系統(tǒng)調(diào)用,為了父進(jìn)程能夠獲知它的消息,子進(jìn)程的進(jìn)程描述符仍然被保留著。一旦父進(jìn)程調(diào)用
73、了wait進(jìn)程描述符就會(huì)被釋放掉。</p><p> TASK_STOPPED(停止)——進(jìn)程停止執(zhí)行,進(jìn)程沒(méi)有投入運(yùn)行也不能投入欲行。通常這種狀態(tài)發(fā)生在接受到SIGSTOP、SIGTTIN、SIGTTOU等信號(hào)的時(shí)候。此外,在調(diào)試期間受到任何信號(hào),都會(huì)使進(jìn)程進(jìn)入這種狀態(tài)。</p><p> 5 設(shè)置當(dāng)前進(jìn)程狀態(tài)</p><p> 內(nèi)核經(jīng)常需要調(diào)整某個(gè)進(jìn)程的狀
74、態(tài)。這時(shí)最好使用set_task_state(task, state); 函數(shù)。該函數(shù)將制定的進(jìn)程設(shè)置為給定的狀態(tài)。必要的時(shí)候,它會(huì)設(shè)置內(nèi)存屏障來(lái)強(qiáng)制其他處理器作重新排序(一般只有在SMP系統(tǒng)中有此必要),否則,它等價(jià)于:Task->state = state;方法set_current_state(state),和set_task_state(current, state)含義是等同的。</p><p>
75、<b> 進(jìn)程上下文</b></p><p> 可執(zhí)行程序代碼是進(jìn)程的重要組成部分。這些代碼從可執(zhí)行文件載入到進(jìn)程的地址空間執(zhí)行。一般程序在用戶空間執(zhí)行。當(dāng)一個(gè)程序調(diào)用執(zhí)行了系統(tǒng)調(diào)用或者觸發(fā)了某個(gè)異常,它就陷入了內(nèi)核空間。此時(shí),我們稱內(nèi)核“代表進(jìn)程執(zhí)行”并處于進(jìn)程上下文中。在此上下文中current宏是有效的。除非在此間隙有更高優(yōu)先級(jí)的進(jìn)程需要執(zhí)行并由調(diào)度器做出了相應(yīng)的調(diào)整,否則在內(nèi)核退
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 眾賞文庫(kù)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- [雙語(yǔ)翻譯]--物流管理外文翻譯--全球化進(jìn)程中的物流管理未來(lái)
- 外文翻譯--- 燃煤鍋爐的燃燒進(jìn)程控制
- 2015年--物流管理外文翻譯--全球化進(jìn)程中物流管理的未來(lái)
- 2015年--物流管理外文翻譯--全球化進(jìn)程中的物流管理未來(lái)
- 關(guān)于景觀都市主義發(fā)展進(jìn)程的探討 外文翻譯
- 城市化進(jìn)程和經(jīng)濟(jì)增長(zhǎng)外文文獻(xiàn)翻譯
- 外文翻譯---解析oracle數(shù)據(jù)庫(kù)后臺(tái)進(jìn)程的功能
- 外文翻譯--制造分析進(jìn)程數(shù)據(jù)使用快速標(biāo)記技術(shù)
- vb課題項(xiàng)目進(jìn)程管理系統(tǒng)設(shè)計(jì)(論文+源代碼+開題報(bào)告+外文翻譯+答辯ppt)
- 存貨管理【外文翻譯】
- 預(yù)算管理【外文翻譯】
- 2015年--物流管理外文翻譯--全球化進(jìn)程中的物流管理未來(lái)(譯文).docx
- 2015年--物流管理外文翻譯--全球化進(jìn)程中的物流管理未來(lái)(原文).pdf
- 外文翻譯--制造分析進(jìn)程數(shù)據(jù)使用快速標(biāo)記技術(shù)
- 績(jī)效管理 外文翻譯
- 績(jī)效管理外文翻譯
- 薪酬管理 外文翻譯
- 設(shè)計(jì)管理外文翻譯
- 營(yíng)銷管理-外文翻譯
- 倉(cāng)儲(chǔ)管理【外文翻譯】
評(píng)論
0/150
提交評(píng)論