新聞中心
隨著互聯(lián)網(wǎng)的發(fā)展,數(shù)據(jù)采集成為了企業(yè)獲取信息的重要手段之一。而MFC作為一種經(jīng)典的Windows開發(fā)框架,其內(nèi)置的多線程機(jī)制可以很好地處理大規(guī)模數(shù)據(jù)采集的需求。本文將介紹如何使用MFC實(shí)現(xiàn)多線程的數(shù)據(jù)庫采集,以及在實(shí)踐中需要注意的問題。

創(chuàng)新互聯(lián)公司是一家專業(yè)提供囊謙企業(yè)網(wǎng)站建設(shè),專注與網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)、H5場(chǎng)景定制、小程序制作等業(yè)務(wù)。10年已為囊謙眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站設(shè)計(jì)公司優(yōu)惠進(jìn)行中。
一、多線程的優(yōu)勢(shì)
在進(jìn)行大規(guī)模數(shù)據(jù)采集時(shí),單線程的效率是非常低下的,容易造成資源的浪費(fèi)和性能的下降。而多線程的優(yōu)勢(shì)在于可以將任務(wù)分割成多個(gè)子任務(wù),并行地執(zhí)行,從而提高采集的效率,減少時(shí)間成本。
MFC提供了多種多線程的支持機(jī)制,包括CWinThread、CMultiThread、CTaskThread等,可以根據(jù)實(shí)際需求選擇合適的方式。
二、數(shù)據(jù)庫采集的實(shí)現(xiàn)過程
以下將介紹一個(gè)簡(jiǎn)單的數(shù)據(jù)庫采集實(shí)現(xiàn)過程,以SQL Server數(shù)據(jù)庫為例。
1. 打開數(shù)據(jù)庫連接
使用AfxDaoInit()函數(shù)初始化ODBC數(shù)據(jù)庫,并打開與SQL Server的連接。如下所示:
CDatabase db;
CString strSQLConnect = _T(“ODBC;Driver={SQL Server};Server=MyServer;Database=MyDatabase”);
db.OpenEx(strSQLConnect);
其中,MyServer表示SQL Server的名稱,MyDatabase表示數(shù)據(jù)庫名稱。
2. 構(gòu)造查詢語句
針對(duì)具體的需求,構(gòu)造相應(yīng)的SQL查詢語句,如:
CString strSql = _T(“SELECT * FROM tb_books WHERE book_author LIKE ‘%George%'”);
其中,tb_books為表名,book_author為字段名稱。
3. 執(zhí)行查詢語句
使用CRecordset的Open()函數(shù)執(zhí)行查詢語句,并將結(jié)果保存在結(jié)果集中,如:
CRecordset rs(&db);
rs.Open(CRecordset::forwardOnly, strSql);
其中,forwardOnly表示的是結(jié)果集的模式,表示只能向前遍歷每一條記錄,而不支持任意方向的移動(dòng)。
4. 處理查詢結(jié)果
利用CRecordset提供的查找、定位、遍歷等方法,處理查詢結(jié)果。例如:
CString strBookName;
while (!rs.IsEOF())
{
rs.GetFieldValue(_T(“book_name”), strBookName);
// 處理查詢結(jié)果,如輸出、保存等操作
rs.MoveNext();
}
其中,GetFieldValue()函數(shù)可以從結(jié)果集中獲取指定字段的值。
三、MFC多線程的實(shí)現(xiàn)
以上是基于單線程的數(shù)據(jù)庫查詢操作,接下來將介紹如何利用多線程機(jī)制,實(shí)現(xiàn)更高效的數(shù)據(jù)采集操作。
1. 創(chuàng)建新的工作線程
在主線程中,創(chuàng)建新的工作線程,并調(diào)用其函數(shù)進(jìn)行后臺(tái)數(shù)據(jù)采集操作。如下所示:
CWinThread* pThread = AfxBeginThread(&MyThreadFunc, NULL);
其中,MyThreadFunc為新線程的執(zhí)行函數(shù)名稱。
2. 實(shí)現(xiàn)多線程采集函數(shù)
針對(duì)具體的數(shù)據(jù)采集需求,實(shí)現(xiàn)多線程的采集函數(shù)。為了能夠在多線程中訪問數(shù)據(jù)庫,需要定義一個(gè)全局的數(shù)據(jù)庫對(duì)象指針:
CDatabase* g_pDb;
并在新線程啟動(dòng)后,為其初始化:
g_pDb = new CDatabase;
CString strSQLConnect = _T(“ODBC;Driver={SQL Server};Server=MyServer;Database=MyDatabase”);
g_pDb->OpenEx(strSQLConnect);
在采集函數(shù)中,通過參數(shù)的方式傳入采集需要的參數(shù),并在函數(shù)內(nèi)部調(diào)用數(shù)據(jù)庫查詢操作,如:
UINT MyThreadFunc(LPVOID pParam)
{
// 獲取采集參數(shù)
CString strKeyword = *(CString*)pParam;
// 構(gòu)建查詢語句
CString strSql;
// …
// 執(zhí)行查詢
CRecordset rs(g_pDb);
rs.Open(CRecordset::forwardOnly, strSql);
// 處理結(jié)果
// …
return 0;
}
其中,參數(shù)pParam是一個(gè)指向void類型的指針,表示傳入的參數(shù)??梢酝ㄟ^強(qiáng)制類型轉(zhuǎn)換的方式,將其轉(zhuǎn)換為需要的類型。
3. 處理多線程采集結(jié)果
在多線程采集完成后,需要將結(jié)果處理??梢栽谥骶€程中,將采集結(jié)果保存在一個(gè)全局變量中,并在新線程執(zhí)行完成后,讀取處理。如下所示:
// 全局變量,用于保存采集結(jié)果
vector g_vBooks;
UINT MyThreadFunc(LPVOID pParam)
{
// …
// 處理結(jié)果
CString strBookName;
while (!rs.IsEOF())
{
rs.GetFieldValue(_T(“book_name”), strBookName);
g_vBooks.push_back(strBookName);
rs.MoveNext();
}
return 0;
}
在新線程執(zhí)行結(jié)束后,可以在主線程中遍歷全局變量,完成對(duì)采集結(jié)果的處理。
四、注意事項(xiàng)
在實(shí)踐中,需要注意以下幾點(diǎn):
1. 數(shù)據(jù)庫連接和關(guān)閉:在使用完畢后,應(yīng)該及時(shí)關(guān)閉數(shù)據(jù)庫連接,釋放資源。
2. 多線程調(diào)用的安全性:不同的線程之間,可能會(huì)同時(shí)訪問數(shù)據(jù)庫資源,需要注意線程安全性。
3. 任務(wù)的拆分和分配:多線程采集最重要的一點(diǎn)是,如何將任務(wù)拆分,并分配給不同的線程。需要根據(jù)實(shí)際情況,靈活選擇。
四、
成都網(wǎng)站建設(shè)公司-創(chuàng)新互聯(lián),建站經(jīng)驗(yàn)豐富以策略為先導(dǎo)10多年以來專注數(shù)字化網(wǎng)站建設(shè),提供企業(yè)網(wǎng)站建設(shè),高端網(wǎng)站設(shè)計(jì),響應(yīng)式網(wǎng)站制作,設(shè)計(jì)師量身打造品牌風(fēng)格,熱線:028-86922220我也有類似的問題需要請(qǐng)教:用MFC進(jìn)行數(shù)據(jù)庫的一些操作處理。新手,真心求助!
inline _RecordsetPtr Connection15::Execute ( _bstr_t CommandText, VARIANT * RecordsAffected, long Options ) {
struct _Recordset * _result = 0;
HRESULT _hr = raw_Execute(CommandText, RecordsAffected, Options, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _RecordsetPtr(_result, false);
}
我的出猜正正現(xiàn)在這個(gè)函數(shù),不穗悔知道該怎清明么處理
內(nèi)存錯(cuò)誤,這個(gè)不好說! 你調(diào)試運(yùn)行,出錯(cuò)之后程序會(huì)停下,你看停在哪的,之后再看什么問題!
關(guān)于MFC中多線程問題
調(diào)整一下編譯選項(xiàng),選擇多線程動(dòng)態(tài)庫支持
(CGEDlg*)lpParameter->m_geApplication…
遇到過這種問題,是msvcrt庫升在windows級(jí)到sp1后造成的,當(dāng)時(shí)我的解決辦法就是靜態(tài)編譯,沒別的方法了。
是哪個(gè)庫函數(shù)調(diào)用出錯(cuò)?
訪問全局變量、讀寫文件,你做了線程之間同步互斥嗎?
可以用MsgWaitForMultipleObjects等待線程完成運(yùn)算,而且不阻塞消息循環(huán)。
能編譯鏈接通過應(yīng)該跟編譯選項(xiàng)沒關(guān)系了。
但是有個(gè)問題:
GetPointOnTerrainFromScreenCoords的VC版本應(yīng)該有3個(gè)參數(shù)才對(duì)呀,只有2個(gè)參數(shù)那是c#和VB的用法。
下面是VC的聲明:
HRESULT GetPointOnTerrainFromScreenCoords ( double screen_x, double screen_y, IPointOnTerrainGE **pPoint)
多線程,計(jì)算過程為全局的東西,怎么可能會(huì)報(bào)錯(cuò)呢?CreateInstance,然后在ThreadProc響應(yīng),其中的所有變量都是全局的,假如與主線程有共用的變量,用CMutex的Lock,UnLock完全可以同步,使用多線程至今未出錯(cuò),請(qǐng)將錯(cuò)誤提示貼出,我也好學(xué)習(xí)下
怎么在基于對(duì)話框的MFC程序中實(shí)現(xiàn)多線程?
基于MFC的對(duì)話框程序加啟動(dòng)進(jìn)度條(轉(zhuǎn))
對(duì)于比較大的程序,在啟動(dòng)的時(shí)候都會(huì)顯示一個(gè)畫面,以告訴用戶程序正在加載,或者顯示一些關(guān)于軟件的信息,如Visual C++,Word, PhotoShop等。
這些啟動(dòng)畫面在Visual C++中怎么實(shí)現(xiàn)呢?對(duì)于文檔/視圖結(jié)構(gòu)的程序,可以直接使用VC提供的SplashWnd組件。可是在基于對(duì)話框的程序卻不能使用SplashWnd組件。因此只能自己來實(shí)現(xiàn)此功能。
因?yàn)轱@示啟動(dòng)畫面的同時(shí)還要進(jìn)行程序的加載工作,所以要用到
多線程
。前尺M(jìn)FC區(qū)分了兩種不同類型的多線程:
用戶界面
(UI)線程和工作者線程。兩者的區(qū)別是UI線程有消息循環(huán),而工作者線程沒有,UI線程能夠創(chuàng)建窗口并處理發(fā)送給窗口的消息。工作者線程用來執(zhí)行后臺(tái)任務(wù),這些后臺(tái)任務(wù)不直接接受用戶輸入,因此不需要窗口和消息循環(huán)。 因?yàn)檫@里要顯示一個(gè)畫面,所以要使用UI線程。
下面結(jié)合我做的一個(gè)小軟件“實(shí)用鬧鐘”來說明如何為對(duì)話框程序制作啟動(dòng)畫面。
打開Visual C++建立一個(gè)對(duì)話框工程Page.
首先準(zhǔn)備一副位圖資源插入到工程中,作為啟動(dòng)時(shí)顯示的畫面。再插入一個(gè)對(duì)話框,設(shè)置ID為IDD_SPLASH。在上面放一個(gè)picture控件,類型設(shè)為”慧念高Bitmap”,圖象選擇剛才插入的位圖。
設(shè)置對(duì)話框的Style為Popup,Border 為None,去掉Title Bar屬性,并調(diào)整對(duì)話框的大小與位圖等大,這樣對(duì)話框顯示的時(shí)候,你看到的只是圖片。打開 ClassWizard為此對(duì)話框建立一個(gè)新類CSplashDlg, 基類為CDialog.
UI線程是由一個(gè)動(dòng)態(tài)可創(chuàng)建的類來控制,該類是從CWinThread派生的,非常類似從CWinApp派生的一個(gè)
應(yīng)用程序
類.打開ClassWizard建立一個(gè)由CWinThread派生的類—-CSplashThread,在SplashThread.h 中加入 #include”SplashDlg.h”,并添加一個(gè)protected型指針變量:
CSplashDlg* m_pSplashDlg; //聲明一個(gè)對(duì)話框指針
下面我們將在UI線程的InitInstance()函數(shù)中調(diào)用剛才創(chuàng)建的對(duì)話框并顯示。
BOOL CSplashThread::InitInstance()
{
::AttachThreadInput(m_nThreadID, AfxGetApp()->m_nThreadID, TRUE );
//:通常系統(tǒng)內(nèi)的每個(gè)線程都有自己的輸入隊(duì)列。本函數(shù)允許線程和進(jìn)程共享輸入隊(duì)列。連接了線程后,輸入焦點(diǎn)、窗口激活、鼠標(biāo)捕獲、鍵盤狀態(tài)以及輸入隊(duì)列狀態(tài)都會(huì)進(jìn)入共享狀態(tài) . (這個(gè)函數(shù)可以不用)
m_pSplashDlg=new CSplashDlg;
m_pSplashDlg->SetEnable(true);
m_pSplashDlg->Create(IDD_SPLASH);
m_pSplashDlg->ShowWindow(SW_SHOW);
return true;
}
為CSplashThread類添加一個(gè)函數(shù)HideSplash(), 用來隱藏啟動(dòng)畫面(即關(guān)閉對(duì)話框)
void CSplashThread::HideSplash()
{
m_pSplashDlg->SendMessage(WM_CLOSE);
}
在ExitInstance()中釋放資源:
int CSplashThread::ExitInstance()
{
m_pSplashDlg->高豎DestroyWindow();
delete m_pSplashDlg;
return CWinThread::ExitInstance();
}
在應(yīng)用程序類CPageApp中包含
頭文件
: #include “SplashThread.h”
并添加兩個(gè)變量:
public://設(shè)為pulic類型,是為了在其他類中能夠訪問
CSplashThread* pSplashThread;
CSplashDlg* m_pSplashDlg;
在InitInstance()中啟動(dòng)UI線程:
pSplashThread = (CSplashThread*) AfxBeginThread(
RUNTIME_CLASS(CSplashThread),
THREAD_PRIORITY_NORMAL,
0, CREATE_SUSPENDED);
ASSERT(pSplashThread->IsKindOf(RUNTIME_CLASS(CSplashThread)));
pSplashThread->ResumeThread();
Sleep(1);
為了讓程序一起動(dòng)就顯示啟動(dòng)畫面,這段代碼應(yīng)該放在InitInstance()最開頭的地方.
啟動(dòng)畫面是顯示了,可是結(jié)束代碼應(yīng)該放在什么地方呢?如果放在InitInstance()的CPageDlg dlg; m_pMainWnd = &dlg; 后面,即在構(gòu)造了主對(duì)話框之后隱藏啟動(dòng)畫面, 程序運(yùn)行時(shí)會(huì)發(fā)現(xiàn),啟動(dòng)畫面結(jié)束后,還要等一會(huì)才能顯示出主對(duì)話框,這樣就達(dá)不到啟動(dòng)畫面應(yīng)有的效果. 更好應(yīng)該在即將顯示主對(duì)話框的時(shí)候隱藏啟動(dòng)畫面. 我的這個(gè)軟件中在主對(duì)話框中定義了5個(gè)子對(duì)話框類的對(duì)象,分別是page1,page2,…page5.
程序啟動(dòng)時(shí)的流程如下:
Page1構(gòu)造 —>Page2構(gòu)造 —>Page3構(gòu)造—> Page4構(gòu)造—> Page5構(gòu)造—> 主對(duì)話框構(gòu)造 —>主對(duì)話框初始化—> Page1初始化—> Page2初始化 —>Page3初始化 Page4初始化—> Page5初始化
由此可見,啟動(dòng)畫面結(jié)束的更好地方應(yīng)該是在 page5的初始化函數(shù)中
BOOL CPage5::OnInitDialog()
{
CDialog::OnInitDialog();
if ( ((CPageApp*)AfxGetApp())->pSplashThread != NULL)
((CPageApp*)AfxGetApp())->pSplashThread->HideSplash();
return TRUE;
}
到此,一個(gè)對(duì)話框程序的啟動(dòng)畫面就這樣完成了.由于是用對(duì)話框作為啟動(dòng)畫面,所以你可以你可以發(fā)揮你的想象力,在對(duì)話框上設(shè)計(jì)出豐富多才的效果來,比如加上Flash,Gif動(dòng)畫等.
在將要處理數(shù)據(jù)的地方,使用 AfxBeginThread開創(chuàng)一個(gè)線程,AfxBeginThread很簡(jiǎn)單是MFC封閉的全局函數(shù),你可以查一下用法,注意過程函數(shù)必須敏舉碧是靜態(tài)的或是全局的。然后將橋舉數(shù)據(jù)通過AfxBeginThread的參數(shù)傳遞給過程函數(shù)去處答銀理。至于計(jì)算后的結(jié)果嗎。建議,你使用向主窗口發(fā)MSG的方法通知給主窗口。
MFC線襪旅程創(chuàng)建函數(shù):AfxBeginThreadWin32線程告兄凳創(chuàng)建函數(shù)塵好:CreateThreadCRT線程創(chuàng)建函數(shù):_beginthread / _beginthreadex 這3種方法都可以
寫一個(gè)線程函者畢數(shù),參數(shù)與歷嫌饑返回值如下所示
UINT ThreadTest(LPVOID pParam);
然后在按鈕里肢返直接用如下函數(shù)啟動(dòng)線程
AfxBeginThread(ThreadTest,NULL);
關(guān)于mfc 多線程采集數(shù)據(jù)庫的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
成都創(chuàng)新互聯(lián)科技公司主營(yíng):網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、小程序制作、成都軟件開發(fā)、網(wǎng)頁設(shè)計(jì)、微信開發(fā)、成都小程序開發(fā)、網(wǎng)站制作、網(wǎng)站開發(fā)等業(yè)務(wù),是專業(yè)的成都做小程序公司、成都網(wǎng)站建設(shè)公司、成都做網(wǎng)站的公司。創(chuàng)新互聯(lián)公司集小程序制作創(chuàng)意,網(wǎng)站制作策劃,畫冊(cè)、網(wǎng)頁、VI設(shè)計(jì),網(wǎng)站、軟件、微信、小程序開發(fā)于一體。
分享題目:MFC多線程數(shù)據(jù)庫采集實(shí)戰(zhàn)(mfc多線程采集數(shù)據(jù)庫)
當(dāng)前路徑:http://www.5511xx.com/article/dhgicij.html


咨詢
建站咨詢
