




已閱讀5頁(yè),還剩25頁(yè)未讀, 繼續(xù)免費(fèi)閱讀
版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
MFC下的多線(xiàn)程編程,作者:陳帥,2008年7月30日,一、MFC 支持的兩種線(xiàn)程:,1. 用戶(hù)界面線(xiàn)程,通常用于處理用戶(hù)輸入及響應(yīng)用戶(hù)生成的事件和消息,并獨(dú)立地相應(yīng)正在應(yīng)用程序其他部分執(zhí)行的線(xiàn)程產(chǎn)生的消息和時(shí)間,并包含一個(gè)消息泵(a Message Pump)。用戶(hù)界面線(xiàn)程包含一個(gè)消息處理的循環(huán),以應(yīng)對(duì)各種事件。,對(duì)于用戶(hù)來(lái)說(shuō)工作線(xiàn)程運(yùn)行在后臺(tái)。這就使得工作線(xiàn)程特別適合去等待一個(gè)事件的發(fā)生。,2. 工作線(xiàn)程,工作線(xiàn)程適用于處理那些不要求用戶(hù)輸入并且比較消耗時(shí)間的其 他任務(wù)(如大規(guī)模的重復(fù)計(jì)算,網(wǎng)絡(luò)數(shù)據(jù)的發(fā)送與接受)。,注意:,在MFC應(yīng)用程序中,所有的線(xiàn)程都是由CWinThread對(duì)象來(lái)表示的; CWinThread是用戶(hù)接口線(xiàn)程的基類(lèi),CWinApp就是CWinThread派生出來(lái)的,在編寫(xiě)用戶(hù)接口線(xiàn)程時(shí),也需要從CWinThread 類(lèi)派生出自己的線(xiàn)程類(lèi); CWinThread同樣是工作線(xiàn)程的基類(lèi),但在編寫(xiě)工作線(xiàn)程的時(shí)候,升值不必刻意地從CWinThread類(lèi)派生出自己的線(xiàn)程類(lèi)對(duì)象。用戶(hù)可以調(diào)用MFC框架的AfxBeginThread幫助函數(shù),會(huì)創(chuàng)建CWinThread對(duì)象。 在Win32API中不區(qū)分兩種線(xiàn)程,它只需要知道線(xiàn)程的起始地址,就可以開(kāi)始執(zhí)行線(xiàn)程。,3.創(chuàng)建MFC的工作線(xiàn)程,(1).編程實(shí)現(xiàn)控制函數(shù),一個(gè)工作線(xiàn)程對(duì)應(yīng)一個(gè)控制函數(shù)。線(xiàn)程執(zhí)行的任務(wù)都應(yīng)編寫(xiě)在控制函數(shù)之中。編寫(xiě)實(shí)現(xiàn)工作線(xiàn)程的控制函數(shù)是創(chuàng)建工作線(xiàn)程的第一步。,控制函數(shù)的原型聲明是:UNIT ControlFunctionName(LPVOID pParam); 其中, UNIT ControlFunctionName:是控制函數(shù)的名字,自定。,參數(shù)pParam:是一個(gè)32位指針值,是啟動(dòng)工作線(xiàn)程時(shí),有調(diào)用的AfxBeginThread()函數(shù)傳遞給工作線(xiàn)程的控制函數(shù)的。這個(gè)值既可以是指向簡(jiǎn)單數(shù)據(jù)類(lèi)型的指針,用來(lái)傳遞int之類(lèi)的數(shù)值,也可是是指向包含了許多參數(shù)的結(jié)構(gòu)體或其他對(duì)象的指針;甚至可以忽略它。,(2).創(chuàng)建并啟動(dòng)工作線(xiàn)程,在進(jìn)程的主線(xiàn)程或其他線(xiàn)程中調(diào)用AfxBeginThread()函數(shù)就可以創(chuàng)建新的線(xiàn)程,并使線(xiàn)程開(kāi)始運(yùn)行。,AfxBeginThread()函數(shù)是MFC提供的幫助函數(shù),有兩個(gè)重載版本,區(qū)別在于使用的入口參數(shù)不同。一個(gè)用于創(chuàng)建并啟動(dòng)用戶(hù)接口線(xiàn)程,一個(gè)用于創(chuàng)建并啟動(dòng)工作線(xiàn)程。,要?jiǎng)?chuàng)建并啟動(dòng)工作線(xiàn)程,必須采用如下的調(diào)用格式:,CWinThread* AfxBeginThread(,AFX_THREADPROC pfnThreadProc,LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );,參數(shù)pfnThreadProc:是一個(gè)指向工作線(xiàn)程的控制函數(shù)的指針,即控制函數(shù)的地址。創(chuàng)建工作線(xiàn)程是必須指定將在此線(xiàn)程內(nèi)部運(yùn)行的控制函數(shù)。,參數(shù)pParam:是一個(gè)指向某種類(lèi)型的數(shù)據(jù)結(jié)構(gòu)指針,執(zhí)行本函數(shù)時(shí),將把這個(gè)指針進(jìn)一步傳遞給此線(xiàn)程的控制函數(shù),使之成為線(xiàn)程控制函數(shù)的入口參數(shù)。,參數(shù)nPriority:通常設(shè)為0。,參數(shù)nStackSize:通常設(shè)為0。,參數(shù)dwCreateFlags :通常設(shè)為0。,參數(shù)dwCreateFlags :通常設(shè)為0。,參數(shù)lpSecurityAttrs:通常設(shè)為NULL。,(3)創(chuàng)建工作線(xiàn)程的例子,struct int n; double* pD; myData; myData ss;/定義了該類(lèi)型的變量,對(duì)該變量的初始化的代碼省略了 UNIT MyCalcFunc(LPVOID pParam) /如果入口函數(shù)為空指針,終止線(xiàn)程 if( pParam=NULL) AfxEndThread(MY_NULL_POINTTER_ERROR); int n=pParam-n; /數(shù)組元素個(gè)數(shù); double* pD=pParam-pD; /指向數(shù)組的第一個(gè)元素; double sum=0; /數(shù)組元素之和; for(int i=0; in; i+) sum+=pDi;/數(shù)組之和; CString bb; bb.Format(“數(shù)組的和是:%d“,sum);/格式化顯示字符串; AfxMessageBox(bb); /顯示結(jié)果; return 0; ,(i) 編程實(shí)現(xiàn)線(xiàn)程控制函數(shù),(2)在程序進(jìn)程的主線(xiàn)程中調(diào)用AfxBeginThread()函數(shù)來(lái)創(chuàng)建并啟動(dòng)運(yùn)行這個(gè)線(xiàn)程。將控制函數(shù)名和結(jié)構(gòu)變量的地址作為參數(shù)來(lái)傳遞,其他的參數(shù)省略,表示使用默認(rèn)值。,AfxBeginThread(MyCalcFunc,一旦調(diào)用了此函數(shù),線(xiàn)程就被創(chuàng)建,并開(kāi)始執(zhí)行線(xiàn)程函數(shù)。當(dāng)數(shù)據(jù)的計(jì)算完成時(shí),函數(shù)將停止運(yùn)行,線(xiàn)程擁有的堆棧和其它的資源都將釋放。CWinThread對(duì)象將被刪除。,3. 創(chuàng)建并啟動(dòng)用戶(hù)界面線(xiàn)程,創(chuàng)建并啟動(dòng)用戶(hù)界面線(xiàn)程一般要經(jīng)過(guò)3個(gè)步驟: 第一步是從CWinThread類(lèi)派生出自己的線(xiàn)程類(lèi); 第二步是改造這個(gè)線(xiàn)程類(lèi),使它能夠完成用戶(hù)所希望的工作; 第三步是創(chuàng)建并啟動(dòng)用戶(hù)界面線(xiàn)程。,(1)從CWinThread類(lèi)派生出自己的線(xiàn)程類(lèi),要?jiǎng)?chuàng)建一個(gè)MFC的用戶(hù)界面線(xiàn)程,所要做的第一件事就是從CWinThread類(lèi)派生出自己的線(xiàn)程類(lèi),一般借助ClassWizard來(lái)做這項(xiàng)工作。,(2)改造自己的線(xiàn)程類(lèi),(i)在這個(gè)線(xiàn)程類(lèi)的.h頭文件中,使用DECLARE_DYNCRATE宏來(lái)聲明這個(gè)類(lèi);在用戶(hù)線(xiàn)程類(lèi)的.cpp實(shí)現(xiàn)文件中,使用IMPLEMENT_DYNCREATE宏來(lái)實(shí)現(xiàn)這個(gè)類(lèi)。,前者的調(diào)用格式是: DECLARE_DYNCRATE(class_name),其中class_name中是實(shí)際的類(lèi)名。,(ii)如果在一個(gè)類(lèi)中宣布使用了DECLARE_DYNCRATE宏,那么就必須在這個(gè)類(lèi)的.cpp實(shí)現(xiàn)文件中,使用IMPLEMENT_DYNCREATE宏。它的調(diào)用格式是: IMPLEMENT_DYNCREATE(class_name, base_class_name) 參數(shù)是實(shí)際的線(xiàn)程類(lèi)名和它的基類(lèi)名。,(iii)這個(gè)線(xiàn)程類(lèi)必須重載它的基類(lèi)(CWinThread類(lèi))的某些成員函數(shù),如該類(lèi)的InitInstance()成員函數(shù);對(duì)于基類(lèi)的其它成員函數(shù),可以有選擇的重載,也可以使用缺省函數(shù)。,創(chuàng)建用戶(hù)界面線(xiàn)程時(shí)相關(guān)成員函數(shù)的重載,(vi) 創(chuàng)建新的用戶(hù)界面窗口類(lèi),如窗口、對(duì)話(huà)框,并添加所需要的用戶(hù)界面控件,然后建立新建的線(xiàn)程類(lèi)與這些用戶(hù)界面窗口類(lèi)的聯(lián)系。,(v)利用類(lèi)向?qū)?,為新建的線(xiàn)程類(lèi)添加控件成員變量,添加響應(yīng)消息的成員函數(shù),為它們編寫(xiě)實(shí)現(xiàn)的代碼,經(jīng)過(guò)以上步驟的改造,用戶(hù)的線(xiàn)程類(lèi)已經(jīng)具備了完成用戶(hù)任務(wù)的能力.,(3)創(chuàng)建并啟用用戶(hù)界面線(xiàn)程,要?jiǎng)?chuàng)建并啟動(dòng)用戶(hù)界面線(xiàn)程,可以使用MFC提供的AfxBeginThread()函數(shù)的另一個(gè)版本,其格式是:,CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );,參數(shù)pThreadClass:是一個(gè)指向CRuntimeClass類(lèi)對(duì)象的指針,該類(lèi)是從CWinThread類(lèi)繼承的。用戶(hù)界面線(xiàn)程運(yùn)行時(shí)類(lèi)就在第一步驟從CWinThread派生的線(xiàn)程類(lèi),本參數(shù)就指向它,在實(shí)際調(diào)用時(shí),一般使用RUNTIME_CLASS 宏將線(xiàn)程類(lèi)指針轉(zhuǎn)化為指向CRuntimeClass對(duì)象的指針。 其他的參數(shù)這和創(chuàng)建啟動(dòng)工作線(xiàn)程時(shí)一樣。,4.終止線(xiàn)程,(1) 正常終止線(xiàn)程,VOID PostQuitMessage()函數(shù)的調(diào)用格式是: VOID PostQuitMessage(int nExitCode); 參數(shù)nExitCode是一個(gè)整數(shù)型值,指定一個(gè)應(yīng)用程序的終止代碼。,PostQuitMessage()函數(shù)發(fā)送一個(gè)WM_QUIT消息到線(xiàn)程的消息隊(duì)列,并立即返回,沒(méi)有返回值。函數(shù)只是簡(jiǎn)單地告訴系統(tǒng),這個(gè)線(xiàn)程要求終止。當(dāng)線(xiàn)程從它的消息隊(duì)列收到一個(gè)WM_QUIT消息時(shí),會(huì)退出它的消息循環(huán),并將控制權(quán)返回給系統(tǒng),同時(shí)把WM_QUIT消息的wParam參數(shù)中的終止代碼也返回給系統(tǒng),線(xiàn)程也就終止了。,(2)提前終止線(xiàn)程,要想在線(xiàn)程尚未完成它的工作時(shí)提前終止線(xiàn)程,只需從線(xiàn)程內(nèi)調(diào)用AfxEndThread函數(shù),就可以強(qiáng)迫線(xiàn)程終止。此函數(shù)的調(diào)用格式是:,Void AfxEndThread(UNIT nExitCode);,參數(shù)nExitCode指定了線(xiàn)程的終止代碼。,執(zhí)行此函數(shù)將停止函數(shù)所在線(xiàn)程的執(zhí)行,撤銷(xiāo)該線(xiàn)程的堆棧,解除所有綁定到此線(xiàn)程動(dòng)態(tài)鏈接庫(kù)DLLs,并從內(nèi)存中刪除此線(xiàn)程。,(3)終止線(xiàn)程另一種方法:,使用Win32 API 提供的TerminateThread()函數(shù),也可以用來(lái)終止一個(gè)正在運(yùn)行的線(xiàn)程,但是它產(chǎn)生的后果是不可預(yù)料的,一般僅用來(lái)終止堆棧中的死線(xiàn)程,而且此函數(shù)本身不做任何內(nèi)存的清除工作。,5.MFC下多線(xiàn)程的同步機(jī)制,(1)基本概念: 在程序中使用多線(xiàn)程時(shí),一般很少有多個(gè)線(xiàn)程能在其生命期內(nèi)進(jìn)行完全獨(dú)立的操作。更多的情況是一些線(xiàn)程進(jìn)行某些處理操作,而其他的線(xiàn)程必須對(duì)其處理結(jié)果進(jìn)行了解。正常情況下對(duì)這種處理結(jié)果的了解應(yīng)當(dāng)在其處理任務(wù)完成后進(jìn)行。,下述對(duì)象是用來(lái)支持同步的: 1)信號(hào)量 2)互斥鎖 3)臨界區(qū) 4)事件,1)信號(hào)量,為了限制使用共享資源的線(xiàn)程數(shù)目,我們應(yīng)該使用信號(hào)量。信號(hào)量是一個(gè)內(nèi)核對(duì)象。它存儲(chǔ)了一個(gè)計(jì)數(shù)器變量來(lái)跟蹤使用共享資源的線(xiàn)程數(shù)目。例如,下面代碼使用CSemaphore類(lèi)創(chuàng)建了一個(gè)信號(hào)量對(duì)象,它確保在給定的時(shí)間間隔內(nèi)(由構(gòu)造函數(shù)第一個(gè)參數(shù)指定)最多只有5個(gè)線(xiàn)程能使用共享資源。還假定初始時(shí)沒(méi)有線(xiàn)程獲得資源:,CSemaphore g_Sem(5, 5);,一旦線(xiàn)程訪(fǎng)問(wèn)共享資源,信號(hào)量的計(jì)數(shù)器就減1.若變?yōu)?,則接下來(lái)對(duì)資源的訪(fǎng)問(wèn)會(huì)被拒絕,直到有一個(gè)持有資源的線(xiàn)程離開(kāi)(也就是說(shuō)釋放了信號(hào)量)。我們可以如下使用:,/ Try to use the shared resource :WaitForSingleObject(g_Sem, INFINITE); / Now the users counter of the semaphore has decremented by one / Use the shared resource / After we done, let other threads use the resource :ReleaseSemaphore(g_Sem, 1, NULL); / Now the users counter of the semaphore has incremented by one,互斥鎖設(shè)計(jì)為對(duì)同步訪(fǎng)問(wèn)共享資源進(jìn)行保護(hù)?;コ怄i在內(nèi)核中實(shí)現(xiàn),因此需要進(jìn)入內(nèi)核模式操縱它們?;コ怄i不僅能在不同線(xiàn)程之間,也可以在不同進(jìn)程之間進(jìn)程同步。要跨進(jìn)程使用,則互斥鎖應(yīng)該是有名的。MFC中使用CMutex類(lèi)來(lái)操縱互斥鎖??梢匀缦路绞绞褂茫?2)互斥鎖,CSingleLock singleLock( ,3)臨界區(qū),臨界區(qū)(Critical Section)是一段獨(dú)占對(duì)某些共享資源訪(fǎng)問(wèn)的代碼,在任意時(shí)刻只允許一個(gè)線(xiàn)程對(duì)共享資源進(jìn)行訪(fǎng)問(wèn)。如果有多個(gè)線(xiàn)程試圖同時(shí)訪(fǎng)問(wèn)臨界區(qū),那么在有一個(gè)線(xiàn)程進(jìn)入后其他所有試圖訪(fǎng)問(wèn)此臨界區(qū)的線(xiàn)程將被掛起,并一直持續(xù)到進(jìn)入臨界區(qū)的線(xiàn)程離開(kāi)。臨界區(qū)在被釋放后,其他線(xiàn)程可以繼續(xù)搶占,并以此達(dá)到用原子方式操作共享資源的目的。,臨界區(qū)在使用時(shí)以CRITICAL_SECTION結(jié)構(gòu)對(duì)象保護(hù)共享資源,并分別用EnterCriticalSection()和LeaveCriticalSection()函數(shù)去標(biāo)識(shí)和釋放一個(gè)臨界區(qū)。所用到的CRITICAL_SECTION結(jié)構(gòu)對(duì)象必須經(jīng)過(guò)InitializeCriticalSection()的初始化后才能使用,而且必須確保所有線(xiàn)程中的任何試圖訪(fǎng)問(wèn)此共享資源的代碼都處在此臨界區(qū)的保護(hù)之下。否則臨界區(qū)將不會(huì)起到應(yīng)有的作用,共享資源依然有被破壞的可能。,MFC為臨界區(qū)提供有一個(gè)CCriticalSection類(lèi),使用該類(lèi)進(jìn)行線(xiàn)程同步處理是非常簡(jiǎn)單的,只需在線(xiàn)程函數(shù)中用CCriticalSection類(lèi)成員函數(shù)Lock()和UnLock()標(biāo)定出被保護(hù)代碼片段即可。,如:/ MFC臨界區(qū)類(lèi)對(duì)象 CCriticalSection g_clsCriticalSection; / 共享資源 char g_cArray10; UINT ThreadProc20(LPVOID pParam) / 進(jìn)入臨界區(qū) g_clsCriticalSection.Lock(); / 對(duì)共享資源進(jìn)行寫(xiě)入操作 for (int i = 0; i 10; i+) g_cArrayi = a; Sleep(1); / 離開(kāi)臨界區(qū) g_clsCriticalSection.Unlock(); return 0; ,4)事件,一般來(lái)說(shuō),事件用于這樣的情形下:當(dāng)指定的動(dòng)作發(fā)生后,一個(gè)線(xiàn)程(或多個(gè)線(xiàn)程)才開(kāi)始執(zhí)行其任務(wù)。例如,一個(gè)線(xiàn)程可能等待必需的數(shù)據(jù)收集完后才開(kāi)始將其保存到硬盤(pán)上。,有兩種事件:手動(dòng)重置型和自動(dòng)重置型。通過(guò)使用事件,我們可以輕松地通知另一個(gè)線(xiàn)程特定的動(dòng)作已經(jīng)發(fā)生了。對(duì)于手動(dòng)重置型事件,線(xiàn)程使用它通知多個(gè)線(xiàn)程特定動(dòng)作已經(jīng)發(fā)生,而對(duì)于自動(dòng)重置型事件,線(xiàn)程使用它只可以通知一個(gè)線(xiàn)程。,在MFC中,CEvent類(lèi)封裝了事件對(duì)象(若在win32中,它是用一個(gè)HANDLE來(lái)表示的)。CEvent的構(gòu)造函數(shù)運(yùn)行我們選擇創(chuàng)建手動(dòng)重置型和自動(dòng)重置型事件。默認(rèn)的創(chuàng)建類(lèi)型是自動(dòng)重置型事件。為了通知正在等待的線(xiàn)程,我們可以調(diào)用CEvent:SetEvent方法,這個(gè)方法將會(huì)讓事件進(jìn)入已通知狀態(tài)。若事件是手動(dòng)重置型,則事件會(huì)保持已通知狀態(tài),直到對(duì)應(yīng)的CEvent:ResetEvent被調(diào)用,這個(gè)方法將使得事件進(jìn)入未通知狀態(tài)。這個(gè)特性使得一個(gè)線(xiàn)程可以通過(guò)一個(gè)SetEvent調(diào)用去通知多個(gè)線(xiàn)程。若事件是自動(dòng)重置型,則所有正在等待的線(xiàn)程中只有一個(gè)線(xiàn)程會(huì)接收到通知。當(dāng)那個(gè)線(xiàn)程接收到通知后,事件會(huì)自動(dòng)進(jìn)入未通知狀態(tài)。,CEvent g_eventStart; UINT ThreadProc1(LPVOID pParam) :WaitForSingleObject(g_eventStart, INFINITE); return 0; UINT ThreadProc2(LPVOID pParam) :WaitForSingleObject(g_eventStart, INFINITE); return 0; ,在這個(gè)例子中,一個(gè)全局的
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 景觀設(shè)計(jì)畢業(yè)答辯方案匯報(bào)
- 《上海汽車(chē)展》課件
- 醫(yī)學(xué)微生物學(xué)試題庫(kù)含答案(附解析)
- 保育員(高級(jí))考試題含參考答案解析
- 8月化學(xué)檢驗(yàn)員(初級(jí))考試題+參考答案解析
- 中學(xué)生物教育教學(xué)研究
- 《海爾品牌戰(zhàn)略案例》課件
- 藥品倉(cāng)儲(chǔ)庫(kù)房貨架光滑度測(cè)試考核試卷
- 電力儀表的節(jié)能技術(shù)考核試卷
- 調(diào)味品與文化傳承的結(jié)合考核試卷
- 基于認(rèn)知模型建構(gòu)與應(yīng)用發(fā)展科學(xué)思維
- 頭療館轉(zhuǎn)讓合同
- 2025年軍隊(duì)文職考試《公共科目》試題與參考答案
- 國(guó)內(nèi)外科研機(jī)構(gòu)績(jī)效管理模式分析
- 2023年高考真題-物理(福建卷) 含答案
- 1型糖尿病飲食宣教
- 《精裝修成品保護(hù)》課件
- 學(xué)校食堂設(shè)備故障應(yīng)急預(yù)案
- 《中小學(xué)生時(shí)間規(guī)劃管理主題班會(huì):做時(shí)間的主人》課件(五套)
- 二年級(jí)乘除法口訣專(zhuān)項(xiàng)練習(xí)1000題
- DB35T 2148-2023 養(yǎng)殖大黃魚(yú)等級(jí)規(guī)格
評(píng)論
0/150
提交評(píng)論