MFC多线程数据库采集实战 (mfc 多线程采集数据库)

随着互联网的发展,数据采集成为了企业获取信息的重要手段之一。而MFC作为一种经典的Windows开发框架,其内置的多线程机制可以很好地处理大规模数据采集的需求。本文将介绍如何使用MFC实现多线程的数据库采集,以及在实践中需要注意的问题。

一、多线程的优势

在进行大规模数据采集时,单线程的效率是非常低下的,容易造成资源的浪费和性能的下降。而多线程的优势在于可以将任务分割成多个子任务,并行地执行,从而提高采集的效率,减少时间成本。

MFC提供了多种多线程的支持机制,包括CWinThread、CMultiThread、CTaskThread等,可以根据实际需求选择合适的方式。

二、数据库采集的实现过程

以下将介绍一个简单的数据库采集实现过程,以SQL Server数据库为例。

1. 打开数据库连接

使用AfxDaoInit()函数初始化ODBC数据库,并打开与SQL Server的连接。如下所示:

CDatabase db;

CString strSQLConnect = _T(“ODBC;Driver={SQL Server};Server=MyServer;Database=MyDatabase”);

db.OpenEx(strSQLConnect);

其中,MyServer表示SQL Server的名称,MyDatabase表示数据库名称。

2. 构造查询语句

针对具体的需求,构造相应的SQL查询语句,如:

CString strSql = _T(“SELECT * FROM tb_books WHERE book_author LIKE ‘%George%'”);

其中,tb_books为表名,book_author为字段名称。

3. 执行查询语句

使用CRecordset的Open()函数执行查询语句,并将结果保存在结果集中,如:

CRecordset rs(&db);

rs.Open(CRecordset::forwardOnly, strSql);

其中,forwardOnly表示的是结果集的模式,表示只能向前遍历每一条记录,而不支持任意方向的移动。

4. 处理查询结果

利用CRecordset提供的查找、定位、遍历等方法,处理查询结果。例如:

CString strBookName;

while (!rs.IsEOF())

{

rs.GetFieldValue(_T(“book_name”), strBookName);

// 处理查询结果,如输出、保存等操作

rs.MoveNext();

}

其中,GetFieldValue()函数可以从结果集中获取指定字段的值。

三、MFC多线程的实现

以上是基于单线程的数据库查询操作,接下来将介绍如何利用多线程机制,实现更高效的数据采集操作。

1. 创建新的工作线程

在主线程中,创建新的工作线程,并调用其函数进行后台数据采集操作。如下所示:

CWinThread* pThread = AfxBeginThread(&MyThreadFunc, NULL);

其中,MyThreadFunc为新线程的执行函数名称。

2. 实现多线程采集函数

针对具体的数据采集需求,实现多线程的采集函数。为了能够在多线程中访问数据库,需要定义一个全局的数据库对象指针:

CDatabase* g_pDb;

并在新线程启动后,为其初始化:

g_pDb = new CDatabase;

CString strSQLConnect = _T(“ODBC;Driver={SQL Server};Server=MyServer;Database=MyDatabase”);

g_pDb->OpenEx(strSQLConnect);

在采集函数中,通过参数的方式传入采集需要的参数,并在函数内部调用数据库查询操作,如:

UINT MyThreadFunc(LPVOID pParam)

{

// 获取采集参数

CString strKeyword = *(CString*)pParam;

// 构建查询语句

CString strSql;

// …

// 执行查询

CRecordset rs(g_pDb);

rs.Open(CRecordset::forwardOnly, strSql);

// 处理结果

// …

return 0;

}

其中,参数pParam是一个指向void类型的指针,表示传入的参数。可以通过强制类型转换的方式,将其转换为需要的类型。

3. 处理多线程采集结果

在多线程采集完成后,需要将结果处理。可以在主线程中,将采集结果保存在一个全局变量中,并在新线程执行完成后,读取处理。如下所示:

// 全局变量,用于保存采集结果

vector g_vBooks;

UINT MyThreadFunc(LPVOID pParam)

{

// …

// 处理结果

CString strBookName;

while (!rs.IsEOF())

{

rs.GetFieldValue(_T(“book_name”), strBookName);

g_vBooks.push_back(strBookName);

rs.MoveNext();

}

return 0;

}

在新线程执行结束后,可以在主线程中遍历全局变量,完成对采集结果的处理。

四、注意事项

在实践中,需要注意以下几点:

1. 数据库连接和关闭:在使用完毕后,应该及时关闭数据库连接,释放资源。

2. 多线程调用的安全性:不同的线程之间,可能会同时访问数据库资源,需要注意线程安全性。

3. 任务的拆分和分配:多线程采集最重要的一点是,如何将任务拆分,并分配给不同的线程。需要根据实际情况,灵活选择。

四、

相关问题拓展阅读:

我也有类似的问题需要请教:用MFC进行数据库的一些操作处理。新手,真心求助!

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);

}

我的出猜正正现在这个函数,不穗悔知道该怎清明么处理

内存错误,这个不好说! 你调试运行,出错之后程序会停下,你看停在哪的,之后再看什么问题!

关于MFC中多线程问题

调整一下编译选项,选择多线程动态库支持

(CGEDlg*)lpParameter->m_geApplication…

遇到过这种问题,是msvcrt库升在windows级到sp1后造成的,当时我的解决办法就是静态编译,没别的方法了。

是哪个库函数调用出错?

访问全局变量、读写文件,你做了线程之间同步互斥吗?

可以用MsgWaitForMultipleObjects等待线程完成运算,而且不阻塞消息循环。

能编译链接通过应该跟编译选项没关系了。

但是有个问题:

GetPointOnTerrainFromScreenCoords的VC版本应该有3个参数才对呀,只有2个参数那是c#和VB的用法。

下面是VC的声明:

HRESULT GetPointOnTerrainFromScreenCoords ( double screen_x, double screen_y, IPointOnTerrainGE **pPoint)

多线程,计算过程为全局的东西,怎么可能会报错呢?CreateInstance,然后在ThreadProc响应,其中的所有变量都是全局的,假如与主线程有共用的变量,用CMutex的Lock,UnLock完全可以同步,使用多线程至今未出错,请将错误提示贴出,我也好学习下

怎么在基于对话框的MFC程序中实现多线程?

基于MFC的对话框程序加启动进度条(转)

对于比较大的程序,在启动的时候都会显示一个画面,以告诉用户程序正在加载,或者显示一些关于软件的信息,如Visual C++,Word, PhotoShop等。

这些启动画面在Visual C++中怎么实现呢?对于文档/视图结构的程序,可以直接使用VC提供的SplashWnd组件。可是在基于对话框的程序却不能使用SplashWnd组件。因此只能自己来实现此功能。

因为显示启动画面的同时还要进行程序的加载工作,所以要用到

多线程

。前尺MFC区分了两种不同类型的多线程:

用户界面

(UI)线程和工作者线程。两者的区别是UI线程有消息循环,而工作者线程没有,UI线程能够创建窗口并处理发送给窗口的消息。工作者线程用来执行后台任务,这些后台任务不直接接受用户输入,因此不需要窗口和消息循环。 因为这里要显示一个画面,所以要使用UI线程。

下面结合我做的一个小软件“实用闹钟”来说明如何为对话框程序制作启动画面。

打开Visual C++建立一个对话框工程Page.

首先准备一副位图资源插入到工程中,作为启动时显示的画面。再插入一个对话框,设置ID为IDD_SPLASH。在上面放一个picture控件,类型设为”慧念高Bitmap”,图象选择刚才插入的位图。

设置对话框的Style为Popup,Border 为None,去掉Title Bar属性,并调整对话框的大小与位图等大,这样对话框显示的时候,你看到的只是图片。打开 ClassWizard为此对话框建立一个新类CSplashDlg, 基类为CDialog.

UI线程是由一个动态可创建的类来控制,该类是从CWinThread派生的,非常类似从CWinApp派生的一个

应用程序

类.打开ClassWizard建立一个由CWinThread派生的类—-CSplashThread,在SplashThread.h 中加入 #include”SplashDlg.h”,并添加一个protected型指针变量:

CSplashDlg* m_pSplashDlg; //声明一个对话框指针

下面我们将在UI线程的InitInstance()函数中调用刚才创建的对话框并显示。

BOOL CSplashThread::InitInstance()

{

::AttachThreadInput(m_nThreadID, AfxGetApp()->m_nThreadID, TRUE );

//:通常系统内的每个线程都有自己的输入队列。本函数允许线程和进程共享输入队列。连接了线程后,输入焦点、窗口激活、鼠标捕获、键盘状态以及输入队列状态都会进入共享状态 . (这个函数可以不用)

m_pSplashDlg=new CSplashDlg;

m_pSplashDlg->SetEnable(true);

m_pSplashDlg->Create(IDD_SPLASH);

m_pSplashDlg->ShowWindow(SW_SHOW);

return true;

}

为CSplashThread类添加一个函数HideSplash(), 用来隐藏启动画面(即关闭对话框)

void CSplashThread::HideSplash()

{

m_pSplashDlg->SendMessage(WM_CLOSE);

}

在ExitInstance()中释放资源:

int CSplashThread::ExitInstance()

{

m_pSplashDlg->高竖DestroyWindow();

delete m_pSplashDlg;

return CWinThread::ExitInstance();

}

在应用程序类CPageApp中包含

头文件

: #include “SplashThread.h”

并添加两个变量:

public://设为pulic类型,是为了在其他类中能够访问

CSplashThread* pSplashThread;

CSplashDlg* m_pSplashDlg;

在InitInstance()中启动UI线程:

pSplashThread = (CSplashThread*) AfxBeginThread(

RUNTIME_CLASS(CSplashThread),

THREAD_PRIORITY_NORMAL,

0, CREATE_SUSPENDED);

ASSERT(pSplashThread->IsKindOf(RUNTIME_CLASS(CSplashThread)));

pSplashThread->ResumeThread();

Sleep(1);

为了让程序一起动就显示启动画面,这段代码应该放在InitInstance()最开头的地方.

启动画面是显示了,可是结束代码应该放在什么地方呢?如果放在InitInstance()的CPageDlg dlg; m_pMainWnd = &dlg; 后面,即在构造了主对话框之后隐藏启动画面, 程序运行时会发现,启动画面结束后,还要等一会才能显示出主对话框,这样就达不到启动画面应有的效果. 更好应该在即将显示主对话框的时候隐藏启动画面. 我的这个软件中在主对话框中定义了5个子对话框类的对象,分别是page1,page2,…page5.

程序启动时的流程如下:

Page1构造 —>Page2构造 —>Page3构造—> Page4构造—> Page5构造—> 主对话框构造 —>主对话框初始化—> Page1初始化—> Page2初始化 —>Page3初始化 Page4初始化—> Page5初始化

由此可见,启动画面结束的更好地方应该是在 page5的初始化函数中

BOOL CPage5::OnInitDialog()

{

CDialog::OnInitDialog();

if ( ((CPageApp*)AfxGetApp())->pSplashThread != NULL)

((CPageApp*)AfxGetApp())->pSplashThread->HideSplash();

return TRUE;

}

到此,一个对话框程序的启动画面就这样完成了.由于是用对话框作为启动画面,所以你可以你可以发挥你的想象力,在对话框上设计出丰富多才的效果来,比如加上Flash,Gif动画等.

在将要处理数据的地方,使用 AfxBeginThread开创一个线程,AfxBeginThread很简单是MFC封闭的全局函数,你可以查一下用法,注意过程函数必须敏举碧是静态的或是全局的。然后将桥举数据通过AfxBeginThread的参数传递给过程函数去处答银理。至于计算后的结果吗。建议,你使用向主窗口发MSG的方法通知给主窗口。

MFC线袜旅程创建函数:AfxBeginThreadWin32线程告兄凳创建函数尘好:CreateThreadCRT线程创建函数:_beginthread / _beginthreadex 这3种方法都可以

写一个线程函者毕数,参数与历嫌饥返回值如下所示

UINT ThreadTest(LPVOID pParam);

然后在按钮里肢返直接用如下函数启动线程

AfxBeginThread(ThreadTest,NULL);

关于mfc 多线程采集数据库的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。


数据运维技术 » MFC多线程数据库采集实战 (mfc 多线程采集数据库)