用VC++50 實 現(xiàn) 多 線 程 的 調 度 和 處 理_第1頁
用VC++50 實 現(xiàn) 多 線 程 的 調 度 和 處 理_第2頁
用VC++50 實 現(xiàn) 多 線 程 的 調 度 和 處 理_第3頁
用VC++50 實 現(xiàn) 多 線 程 的 調 度 和 處 理_第4頁
用VC++50 實 現(xiàn) 多 線 程 的 調 度 和 處 理_第5頁
已閱讀5頁,還剩4頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

用VC++5.0實現(xiàn)多線程的調度和處理一多任務,多進程和多線程Windows95和WindowsNT操作系統(tǒng)支持多任務調度和處理,基于該功能所提供的多任務空間,程序員可以完全控制應用程序中每一個片段的運行,從而編寫高效率的應用程序。所謂多任務通常包括這樣兩大類:多進程和多線程。進程是指在系統(tǒng)中正在運行的一個應用程序;線程是系統(tǒng)分配處理器時間資源的基本單元,或者說進程之內獨立執(zhí)行的一個單元。對于操作系統(tǒng)而言,其調度單元是線程。一個進程至少包括一個線程,通常將該線程稱為主線程。一個進程從主線程的執(zhí)行開始進而創(chuàng)建一個或多個附加線程,就是所謂基于多線程的多任務。開發(fā)多線程應用程序可以利用32位Windows環(huán)境提供的Win32API接口函數(shù),也可以利用VC++中提供的MFC類庫進行開發(fā)。多線程編程在這兩種方式下原理是一樣的,用戶可以根據(jù)需要選擇相應的工具。本文重點講述用VC++5.0提供的MFC類庫實現(xiàn)多線程調度與處理的方法以及由線程多任務所引發(fā)的同步多任務特征,最后詳細解釋一個實現(xiàn)多線程的例程。二基于MFC的多線程編程1MFC對多線程的支持MFC類庫提供了多線程編程支持,對于用戶編程實現(xiàn)來說更加方便。非常重要的一點就是,在多窗口線程情況下,MFC直接提供了用戶接口線程的設計。MFC區(qū)分兩種類型的線程:輔助線程(WorkerThread)和用戶界面線程(UserInterfaceThread)。輔助線程沒有消息機制,通常用來執(zhí)行后臺計算和維護任務°MFC為用戶界面線程提供消息機制,用來處理用戶的輸入,響應用戶產生的事件和消息。但對于Win32的API來說,這兩種線程并沒有區(qū)別,它只需要線程的啟動地址以便啟動線程執(zhí)行任務。用戶界面線程的一個典型應用就是類CWinApp,大家對類CwinApp都比較熟悉,它是CWinThread類的派生類,應用程序的主線程是由它提供,并由它負責處理用戶產生的事件和消息。類CwinThread是用戶接口線程的基本類。CWinThread的對象用以維護特定線程的局部數(shù)據(jù)。因為處理線程局部數(shù)據(jù)依賴于類CWinThread,所以所有使用MFC的線程都必須由MFC來創(chuàng)建。例如,由run-time函數(shù)—beginthreadex創(chuàng)建的線程就不能使用任何MFCAPI。2輔助線程和用戶界面線程的創(chuàng)建和終止要創(chuàng)建一個線程,需要調用函數(shù)AfxBeginThread。該函數(shù)通過參數(shù)重載具有兩種版本,分別對應輔助線程和用戶界面線程。無論是輔助線程還是用戶界面線程,都需要指定額外的參數(shù)以修改優(yōu)先級,堆棧大小,創(chuàng)建標志和安全特性等。函數(shù)AfxBeginThread返回指向CWinThread類對象的指針。創(chuàng)建助于線程相對簡單。只需要兩步:實現(xiàn)控制函數(shù)和啟動線程。它并不必須從CWinThread派生一個類。簡要說明如下:實現(xiàn)控制函數(shù)。控制函數(shù)定義該線程。當進入該函數(shù),線程啟動;退出時,線程終止。該控制函數(shù)聲明如下:UINTMyControllingFunction(LPVOIDpParam);該參數(shù)是一個單精度32位值。該參數(shù)接收的值將在線程對象創(chuàng)建時傳遞給構造函數(shù)??刂坪瘮?shù)將用某種方式解釋該值??梢允菙?shù)量值,或是指向包括多個參數(shù)的結構的指針,甚至可以被忽略。如果該參數(shù)是指結構,則不僅可以將數(shù)據(jù)從調用函數(shù)傳給線程,也可以從線程回傳給調用函數(shù)。如果使用這樣的結構回傳數(shù)據(jù),當結果準備好的時候,線程要通知調用函數(shù)。當函數(shù)結束時,應返回一個UINT類型的值值,指明結束的原因。通常,返回0表明成功,其它值分別代表不同的錯誤。啟動線程。由函數(shù)AfxBeginThread創(chuàng)建并初始化一個CWinThread類的對象,啟動并返回該線程的地址。則線程進入運行狀態(tài)。舉例說明。下面用簡單的代碼說明怎樣定義一個控制函數(shù)以及如何在程序的其它部分使用。UINTMyThreadProc(LPVOIDpParam)(CMyObject*pObject=(CMyObject*)pParam;if(pObject==NULL||!pObject->IsKindOf(RUNTIME_CLASS(CMyObject)))return-1;//非法參數(shù)//具體實現(xiàn)內容return0;//線程成功結束}〃在程序中調用線程的函數(shù)pNewObject=newCMyObject;AfxBeginThread(MyThreadProc,pNewObject);創(chuàng)建用戶界面線程有兩種方法。第一種方法,首先從CWinTread類派生一個類(注意必須要用宏DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE對該類進行聲明和實現(xiàn));然后調用函數(shù)AfxBeginThread創(chuàng)建CWinThread派生類的對象進行初始化啟動線程運行。除了調用函數(shù)AfxBeginThread之夕卜,也可以采用第二種方法,即先通過構造函數(shù)創(chuàng)建類CWinThread的一個對象,然后由程序員調用函數(shù)::CreateThread來啟動線程。通常類CWinThread的對象在該線程的生存期結束時將自動終止,如果程序員希望自己來控制,則需要將m_bAutoDelete設為FALSEo這樣在線程終止之后類CWinThread對象仍然存在,只是在這種情況下需要手動刪除CWinThread對象。通常線程函數(shù)結束之后,線程將自行終止。類CwinThread將為我們完成結束線程的工作。如果在線程的執(zhí)行過程中程序員希望強行終止線程的話,則需要在線程內部調用AfxEndThread(nExitCode)。其參數(shù)為線程結束碼。這樣將終止線程的運行,并釋放線程所占用的資源。如果從另一個線程來終止該線程,則必須在兩個線程之間設置通信方法。如果從線程外部來終止線程的話,還可以使用Win32函數(shù)(CWinThread類不提供該成員函數(shù)):BOOLTerminateThread(HANDLEhThread,DWORDdwExitcode)。但在實際程序設計中對該函數(shù)的使用一定要謹慎,因為一旦該命令發(fā)出,將立即終止該線程,并不釋放線程所占用的資源,這樣可能會引起系統(tǒng)不穩(wěn)定。如果所終止的線程是進程內的最后一個線程,則在該線程終止之后進程也相應終止。3進程和線程的優(yōu)先級問題在Windows95和WindowsNT操作系統(tǒng)當中,任務是有優(yōu)先級的,共有32級,從0到31,系統(tǒng)按照不同的優(yōu)先級調度線程的運行。1)0-15級是普通優(yōu)先級,線程的優(yōu)先級可以動態(tài)變化。高優(yōu)先級線程優(yōu)先運行,只有高優(yōu)先級線程不運行時,才調度低優(yōu)先級線程運行。優(yōu)先級相同的線程按照時間片輪流運行。2)16-30級是實時優(yōu)先級,實時優(yōu)先級與普通優(yōu)先級的最大區(qū)別在于相同優(yōu)先級進程的運行不按照時間片輪轉,而是先運行的線程就先控制CPU,如果它不主動放棄控制,同級或低優(yōu)先級的線程就無法運行。一個線程的優(yōu)先級首先屬于一個類,然后是其在該類中的相對位置。線程優(yōu)先級的計算可以如下式表示:線程優(yōu)先級二進程類基本優(yōu)先級+線程相對優(yōu)先級進程類的基本優(yōu)先級:IDLE_PROCESS_CLASSNORMAL_PROCESS_CLASSHIGH_PROCESS_CLASSREAL_TIME_PROCESS_CLASS線程的相對優(yōu)先級:THREAD_PRIORITY_IDLE(最低優(yōu)先級,僅在系統(tǒng)空閑時執(zhí)行)THREAD_PRIORITY_LOWESTTHREAD_PRIORITY_BELOW_NORMALTHREAD_PRIORITY_NORMAL(缺?。㏕HREAD_PRIORITY_ABOVE_NORMALTHREAD_PRIORITY_HIGHESTTHREAD_PRIORITY_CRITICAL(非常高的優(yōu)先級)4線程同步問題

編寫多線程應用程序的最重要的問題就是線程之間的資源同步訪問。因為多個線程在共享資源時如果發(fā)生訪問沖突個結結果新數(shù)通常會產生不正確的結果。例如,一個線程正在更新一個結結果新數(shù)構的內容的同時另一個線程正試圖讀取同一個結構。,我們將無法得知所讀取的數(shù)據(jù)是什么狀態(tài):舊數(shù)據(jù),據(jù),還是二者的混合?MFC提供了一組同步和同步訪問類來解決這個問題,包括:同步對象:CSyncObject,CSemaphore,CMutex,CcriticalSection和CEvent;同步訪問對象:CMultiLock和CSingleLock。同步類用于當訪問資源時保證資源的整體性。其中CsyncObject是其它四個同步類的基類,不直接使用。信號同步類CSemaphore通常用于當一個應用程序中同時有多個線程訪問一個資源(例如,應用程序允許對同一個Document有多個View)的情況;事件同步類CEvent通常用于在應用程序訪問資源之前應用程序必須等待(比如,在數(shù)據(jù)寫進一個文件之前數(shù)據(jù)必須從通信端口得到)的情況;而對于互斥同步類CMutex和臨界區(qū)同步類CcriticalSection都是用于保證一個資源一次只能有一個線程訪問,二者的不同之處在于前者允許有多個應用程序使用該資源(例如,該資源在一個DLL當中)而后者則不允許對同一個資源的訪問超出進程的范疇,而且使用臨界區(qū)的方式效率比較高。同步訪問類用于獲得對這些控制資源的訪問。CMultiLock和CSingleLock的區(qū)別僅在于是需要控制訪問多個還是單個資源對象。5同步類的使用方法解決同步問題的一個簡單的方法就是將同步類融入共享類當中,通常我們把這樣的共享類稱為線程安全類。下面舉例來說明這些同步類的使用方法。比如,一個用以維護一個帳戶的連接列表的應用程序。該應用程序允許3個帳戶在不同的窗口中檢測,但一次只能更新一個帳戶。當一個帳戶更新之后,需要將更新的數(shù)據(jù)通過網絡傳給一個數(shù)據(jù)文檔。該例中將使用3種同步類。由于允許一次檢測3個帳戶,使用CSemaphore來限制對3個視窗對象的訪問。當更新一個帳目時,應用程序使用CCriticalSection來保證一次只有一個帳目更新。在更新成功之后,發(fā)CEvent信號,該信號釋放一個等待接收信號事件的線程。該線程將新數(shù)據(jù)傳給數(shù)據(jù)文檔。要設計一個線程安全類,首先根據(jù)具體情況在類中加入同步類做為數(shù)據(jù)成員。在例子當中,可以將一個CSemaphore類的數(shù)據(jù)成員加入視窗類中,一個CCriticalSection類數(shù)據(jù)成員加入連接列表類,而一個CEvent數(shù)據(jù)成員加入數(shù)據(jù)存儲類中。然后,在使用共享資源的函數(shù)當中,將同步類與同步訪問類的一個鎖對象聯(lián)系起來。艮L在訪問控制資源的成員函數(shù)中應該創(chuàng)建一個CSingleLock或CMultiLock的對象并調用該對象的Lock函數(shù)。當訪問結束之后,調用UnLock函數(shù),釋放資源。用這種方式來設計線程安全類比較容易。在保證線程安全的同時,省去了維護同步代碼的麻煩,這也正是OOP的思想。但是使用線程安全類方法編程比不考慮線程安全要復雜,尤其體現(xiàn)在程序調試過程中。而且線程安全編程還會損失一部分效率,比如在單CPU計算機中多個線程之間的切換會占用一部分資源。三編程實例下面以VC++5.0中--個簡單的基于對話框的MFC例程來說明實現(xiàn)多線程任務調度與處理的方法,下面加以詳細解釋。在該例程當中定義兩個用戶界面線程,一個顯示線程(CDisplayThread)和一個計數(shù)線程(CCounterThread)。這兩個線程同時操作一個字符串變量m_strNumber,其中顯示線程將該字符串在一個列表框中顯示,而計數(shù)線程則將該字符串中的整數(shù)加1。在例程中,可以分別調整進程、計數(shù)線程和顯示線程的優(yōu)先級。例程中的同步機制使用CMutex和CSingleLock來保證兩個線程不能同時訪問該字符串。同步機制執(zhí)行與否將明顯影響程序的執(zhí)行結果。在該例程中允許將將把兩個線程暫時掛起,以查看運行結果。例程中還允許查看計數(shù)線程的運行。該例程中所處理的問題也是多線程編程中非常具有典型意義的問題。在該程序執(zhí)行時主要有三個用于調整優(yōu)先級的組合框,三個分別用于選擇同步機制、顯示計數(shù)線程運行和掛起線程的復選框以及一個用于顯示運行結果的列表框。在本程序中使用了兩個線程類CCounterThread和CDisplayThread,這兩個線程類共同操作定義在CMutexesDlg中的字符串對象m_strNumber。本程序對同步類CMutex的使用方法就是按照本文所講述的融入的方法來實現(xiàn)的。同步訪問類CSingleLock的鎖對象則在各線程的具體實現(xiàn)中定義。下面介紹該例程的具體實現(xiàn):利用AppWizard生成一個名為Mutexes基于對話框的應用程序框架。利用對話框編輯器在對話框中填加以下內容:三個組合框,三個復選框和一個列表框。三個組合框分別允許改變進程優(yōu)先級和兩個線程優(yōu)先級,其ID分別設置為:IDC_PRIORITYCLASS、IDC_DSPYTHRDPRIORITY和IDC_CNTRTHRDPRIORITY。三個復選框分別對應著同步機制選項、顯示計數(shù)線程執(zhí)行選項和暫停選項,其ID分別設置為IDC_SYNCHRONIZE、IDC_SHOWCNTRTHRD和IDC_PAUSE。列表框用于顯示線程顯示程序中兩個線程的共同操作對象m_strNumber,其ID設置為IDC_DATABOX。創(chuàng)建類CWinThread的派生類CExampleThread。該類將作為本程序中使用的兩個線程類:CCounterThread和CDisplayThread的父類。這樣做的目的僅是為了共享兩個線程類的共用變量和函數(shù)。在CExampleThread的頭文件中填加如下變量:CMutexesDlg*m_pOwner;//指向類CMutexesDlg指針BOOLm_bDone;//用以控制線程執(zhí)行及函數(shù):voidSetOwner(CMutexesDlg*pOwner)(m_pOwner二pOwner;};//取類CMutexesDlg的指針然后在構造函數(shù)當中對成員變量進行初始化:m_bDone二FALSE;//初始化允許線程運行m_pOwner二NULL;//將該指針置為空m_bAutoDelete二FALSE;//要求手動刪除線程對象創(chuàng)建兩個線程類CCounterThread和CdisplayThread。這兩個線程類是CExampleThread的派生類。分別重載兩個線程函數(shù)中的::Run()函數(shù),實現(xiàn)各線程的任務。在這兩個類當中分別加入同步訪問類的鎖對象sLock,這里將根據(jù)同步機制的復選與否來確定是否控制對共享資源的訪問。不要忘記需要加入頭文件#include"afxmt.h”。計數(shù)線程::Run()函數(shù)的重載代碼為:intCCounterThread::Run()(BOOLfSyncChecked;//同步機制復選檢測unsignedintnNumber;//存儲字符串中整數(shù)if(m_pOwner==NULL)return-1;〃將同步對象同鎖對象聯(lián)系起來CSingleLocksLock(&(m_pOwner->m_mutex));while(!m_bDone)//控制線程運行,為終止線程服務(//取同步機制復選狀態(tài)fSyncChecked=m_pOwner->IsDlgButtonChecked(IDC_SYNCHRONIZE);〃確定是否使用同步機制if(fSyncChecked)sLock.Lock();〃讀取整數(shù)_stscanf((LPCTSTR)m_pOwner->m_strNumber,_T("%d"),&nNumber);nNumber++;//加1m_pOwner->m_strNumber.Empty();//字符串置空while(nNumber!=0)//更新字符串(m_pOwner->m_strNumber+=(TCHAR)('0'+nNumber%10);nNumber/=10;}//調整字符串順序m_pOwner->m_strNumber.MakeReverse();//如果復選同步機制,釋放資源if(fSyncChecked)sLock.Unlock();//確定復選顯示計數(shù)線程if(m_pOwner->IsDlgButtonChecked(IDC_SHOWCNTRTHRD))m_pOwner->AddToListBox(_T("Counter:Add1"));}//結束whilem_pOwner->PostMessage(WM_CLOSE,0,0L);return0;}顯示線程的::Run()函數(shù)重載代碼為:intCDisplayThread::Run()(BOOLfSyncChecked;CStringstrBuffer;ASSERT(m_pOwner!=NULL);if(m_pOwner==NULL)return-1;CSingleLocksLock(&(m_pOwner->m_mutex));while(!m_bDone)(fSyncChecked=m_pOwner->IsDlgButtonChecked(IDC_SYNCHRONIZE);if(fSyncChecked)sLock.Lock();//構建要顯示的字符串strBuffer=_T("Display:");strBuffer+=m_pOwner->m_strNumber;if(fSyncChecked)sLock.Unlock();//將字符串加入到列表框中m_pOwner->AddToListBox(strBuffer);}//結束whilem_pOwner->PostMessage(WM_CLOSE,0,0L);return0;}3在CMutexesDlg的頭文件中加入如下成員變量:CStringm_strNumber;//線程所要操作的資源對象CMutexm_mutex;//用于同步機制的互斥量CCounterThread*m_pCounterThread;//指向計數(shù)線程的指針CDisplayThread*m_pDisplayThread;//指向顯示線程的指針首先在對話框的初始化函數(shù)中加入如下代碼對對話框進行初始化:BOOLCMutexesDlg::OnInitDialog()(〃初始化進程優(yōu)先級組合框并置缺省為NORMALCComboBox*pBox;pBox=(CComboBox*)GetDlgItem(IDC_PRIORITYCLASS);ASSERT(pBox!=NULL);if(pBox!=NULL)(pBox->AddString(_T("Idle"));pBox->AddString(_T("Normal"));pBox->AddString(_T("High"));pBox->AddString(_T("Realtime"));pBox->SetCurSel(1);}//初始化顯示線程優(yōu)先級組合框并置缺省為NORMALpBox=(CComboBox*)GetDlgItem(IDC_DSPYTHRDPRIORITY);ASSERT(pBox!=NULL);if(pBox!=NULL)(pBox->AddString(_T("Idle"));pBox->AddString(_T("Lowest"));pBox->AddString(_T("Belownormal"));pBox->AddString(_T("Normal"));pBox->AddString(_T("Abovenormal"));pBox->AddString(_T("Highest"));pBox->AddString(_T("Timecritical"));pBox->SetCurSel(3);}//初始化計數(shù)線程優(yōu)先級組合框并置缺省為NORMALpBox=(CComboBox*)GetDlgItem(IDC_CNTRTHRDPRIORITY);ASSERT(pBox!=NULL);if(pBox!=NULL)(pBox->AddString(_T("Idle"));pBox->AddString(_T("Lowest"));pBox->AddString(_T("Belownormal"));pBox->AddString(_T("Normal"));pBox->AddString(_T("Abovenormal"));pBox->AddString(_T("Highest"));pBox->AddString(_T("Timecritical"));pBox->SetCurSel(3);}//初始化線程掛起復選框為掛起狀態(tài)CButton*pCheck=(CButton*)GetDlgItem(IDC_PAUSE);pCheck->SetCheck(1);//初始化線程m_pDisplayThread=(CDisplayThread*)AfxBeginThread(RUNTIME_CLASS(CDisplayThread),THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);m_pDisplayThread->SetOwner(this);m_pCounterThread=(CCounterThread*)AfxBeginThread(RUNTIME_CLASS(CCounterThread),THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);m_pCounterThread->SetOwner(this);}然后填加成員函數(shù):voidAddToListBox(LPCTSTRszBuffer);//用于填加列表框顯示該函數(shù)的實現(xiàn)代碼為:voidCMutexesDlg::AddToListBox(LPCTSTRszBuffer)(CListBox*pBox=(CListBox*)GetDlgItem(IDC_DATABOX);ASSERT(pBox!=NULL);if(pBox!=NULL)(intx=pBox->AddString(szBuffer);pBox->SetCurSel(x);if(pBox->GetCount()>100)pBox->DeleteString(0);}}然后利用ClassWizard填加用于調整進程優(yōu)先級、兩個線程優(yōu)先級以及用于復選線程掛起的函數(shù)。調整進程優(yōu)先級的代碼為:voidCMutexesDlg::OnSelchangePriorityclass()(DWORDdw;〃取焦點選項CComboBox*pBox=(CComboBox*)GetDlgItem(IDC_PRIORITYCLASS);intnCurSel=pBox->GetCurSel();switch(nCurSel)(case0:dw=IDLE_PRIORITY_CLASS;break;case1:default:dw=NORMAL_PRIORITY_CLASS;break;case2:dw=HIGH_PRIORITY_CLASS;break;case3:dw=REALTIME_PRIORITY_CLASS;break;}SetPriorityClass(GetCurrentProcess(),dw);//調整優(yōu)先級}由于調整兩個線程優(yōu)先級的代碼基本相似,單獨設置-個函數(shù)根據(jù)不同的ID來調整線程優(yōu)先級。該函數(shù)代碼為:voidCMutexesDlg::OnPriorityChange(UINTnID)ASSERT(nID==IDC_CNTRTHRDPRIORITY||nID==IDC_DSPYTHRDPRIORITY);DWORDdw;//取對應該ID的焦點選項CComboBox*pBox=(CComboBox*)GetDlgItem(nID);intnCurSel=pBox->GetCurSel();switch(nCurSel)(case0:dw=(DWORD)THREAD_PRIORITY_IDLE;break;case1:dw=(DWORD)THREAD_PRIORITY_LOWEST;break;case2:dw=(DWORD)THREAD_PRIORITY_BELOW_NORMAL;break;case3:default:dw=(DWORD)THREAD_PRIORITY_NORMAL;break;case4:dw=(DWORD)THREAD_PRIORITY_ABOVE_NORMAL;break;case5:dw=(DWORD)THREAD_PRIORITY_HIGHEST;break;case6:dw=(DWORD)THREAD_PRIORITY_TIME_CRITICAL;break;}if(nID==IDC_CNTRTHRDPRIORITY)m_pCounterThread->SetThreadPriority(dw);//調整計數(shù)線程優(yōu)先級elsem_pDisplayThread->SetThreadPriority(dw);//調整顯示線程優(yōu)先級}這樣線程優(yōu)先級的調整只需要根據(jù)不同的ID來調用該函數(shù):voidCMutexesDlg::OnSelchangeDspythrdpriority()(OnPriorityChange(IDC_DSPYTHRDPRIORITY);}voidCMutexesDlg::OnSelchangeCntrthrdpriority()(OnPriorityChange(IDC_CNTRTHRDPRIORITY);}復選線程掛起的實現(xiàn)代碼如下:voidCMutexesDlg::OnPause()(〃取掛起復選框狀態(tài)CButton*pCheck=(CButton*)GetDlgItem(IDC_PAUSE);BOOLbPaused=((pCheck->GetState()&0x003)!=0);if(bPaused)(m_pCounterThread->SuspendThread();m_pDisplayThread->SuspendThread();}//掛

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論