导航:首页 > 编程语言 > vc2013mfc多线程编程

vc2013mfc多线程编程

发布时间:2022-08-14 19:58:21

1. 关于MFC中多线程问题

是哪个库函数调用出错?

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

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

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

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

下面是VC的声明:

HRESULT ([in] double screen_x,[in] double screen_y,[out, retval] IPointOnTerrainGE **pPoint)

2. MFC多线程编程的几点经验

1、不要在子线程操作UI控件
2、如果你操作了,也绝对不能调用UpdateData来更新界面,否则程序Crash
3、这一条建立在第一条基础上---你在子线程操作UI控件,不可以让主线程等待某些条件(如等待子线程关闭,而子线程正在操作UI、等待进

入临界区,而子线程已经进入,并且操作UI),否则会出现假死...
4、最好方案:子线程操作数据,完成之后,通知主线程进行更新....

3. MFC的多线程问题:我做了个界面,上面有几个按钮,如查询数据库,显示结果,等。

在VC++中利用MFC编程时,线程被分为工作者线程和用户界面线程两大类。前者用于处理后台任务,执行后台任务并不会耽搁用户对应用程序的使用,即用户操作无需等待后台任务的完成。后者常用来独立的处理用户输入和响应用户事件。
一个工作者线程的实现相当的简单,只需要编写线程控制函数和启动函数就好。启动函数:
CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
用户界面线程的实现通常需要派生线程类、重载成员函数和启动用户界面线程。从MFC的CWindThread派生用户界面线程类。父类CWinThread需要重载的函数主要有:InitInstance、ExitInstance和Run。其中InitInstance必须重载,而Run函数除非必要,一般无需重载。其中,启动函数:
CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
建议学习Visual C++6.0编程使用技术与案例,看看多线程编程。。。。

4. VC/MFC 动态创建多线程

1. 因为你是MFC程序,建议使用AfxBeginThread()来创建新线程。AfxBeginThread()的内部会做一些相应的初始化,再调用CreateThread()API。 线程处理函数也就是一个普通的函数,但是其声明形式有规定的,如下:
DWORD WINAPI ThreadProc (LPVOID pParam);
线程函数的名字由你自己定,但是格式必须是什么这个声明形式。比如:
DWORD WINAPI MyThreadFunction (LPVOID pParam)
{
// 函数体,这里你写你的处理代码。
// 只是在理解上,要注意的是,这个线程函数体里面的代码是
// 在新的线程中运行。虽然在源代码上,这里面的代码和其他的代码
// 存在于同一个文件中
}

“可是要在程序运行的才创建的线程,要怎么处理呢”--》不明白你的这个子问题的意思。
新的线程都是在程序运行起来之后,由相应的创建函数创建的。没有哪个线程是在编译时创建的啊。

2. 同一个线程处理函数的代码可以被多个线程共享的。可就是说,你可以只定义一个线程函数。不同的线程创建起来后,运行相同的代码。可以通过传递不同的参数(这个参数可以在创建新线程时从外面传递进去),来让线程函数体内的代码有不同的运行逻辑。
DWORD WINAPI MyThreadFunction (LPVOID pParam /*线程的参数*/)
{
int nMyParam = (int)pParam;
if ( 0 == nMyParam ) { ... }
else if ( 1 == nMyParam ) { ...}
else if (...) {...}
}
对于线程函数的参数,它是LPVOID,但是你在外面可以给他传递一个整形,或者指针,然后在线程函数体内强制转型回来使用。真正使用什么数据类型,与你自己控制。

在理解上,也要注意理解多个线程运行同一份代码的意思。
如果多个线程的线程函数读写同一个全局变量或者访问同一个资源,就需要做同步控制。使用临界区,Mutex等同步对象来控制。

对于多线程的运行机制的理解,比较重要。
理解了之后,你才能游刃有余地控制它。要不然,很容易带来问题。

5. 求mfc线程问题,

子线程中不能操作主线程的控件具,体实现方法见上个提问,另外,UpdateData不要在子线程中用会卡的!

以下是我搜集的MFC多线程应注意的事项,很乱但很有用:

--------------------------------------------------------------------------------

MFC多线程编程注意事项 -
--------------------------------------------------------------------------------

关于启动线程时传输窗口对象(指针?句柄?)的问题:

在选择菜单中的开始线程后:
void cmainframe::onmenu_start()
{
...
afxbeginthread(mythread, this);
...
}

线程函数如下:
uint mythread(lpvoid pparam)
{
cmainframe* pmainfrm = (cmainframe *)pparam;
...
}

问题一:
这样的代码是不是有问题?
(文档中说线程间不能直接传输mfc对象的指针,应该通过传输句柄实现)

问题二:
这样使用开始好像没有问题,直接通过pmainfrm访问窗口中的view都正常。
但发现访问状态条时:
pmainfrm->m_wndstatusbar.setpanetext(2, "test);
出现debug assertion failed!(在窗口线程中没有问题)
位置是wincore.cpp中的
assert((p = pmap->lookuppermanent(m_hwnd)) != null ||
(p = pmap->lookuptemporary(m_hwnd)) != null);
为什么访问view能正常,但访问状态条时不可以呢?

问题三:
如果通过传输句柄实现,怎样做呢?
我用下面的代码执行时有问题:
void cmainframe::onmenu_start()
{
...
hwnd hwnd = getsafehwnd();
afxbeginthread(mythread, hwnd);
...
}

uint mythread(lpvoid pparam)
{
cmainframe* pmainfrm = (cmainframe *)(cwnd::fromhandle((hwnd)pparam));
...
}
执行时通过线程中得到pmainfrm,访问其成员时不正常。

网友:hewwatt
大致原因解释如下:
1. mfc的大多数类不是线程安全的,cwnd及其消息路由是其中之最
2. mfc界面类的大多数方法,最后都是通过sendmessage实现的,而消息处理的
过程中会引发其他消息的发送及处理。如果消息处理函数本身不是线程安全的
你从工作线程中调用这些方法迟早会同你界面线程的用户消息响应发生冲突
3. cxxxx::fromhandle会根据调用者所在线程查表,如果查不到用户创建的cxxxx
对应对象,它会创建一个临时对象出来。由于你在工作线程中调用该方法,当然不可能查到界面主线程中你所建立起来的那个对象了。这时mfc会你创建一个临时对象并返回给你,你根本不可能期望它的成员变量会是有意义的。

所以要用也只能用cwnd::fromhandle,因为它只包含一个m_hwnd成员。 不过,要记住
跨线程直接或间接地调用::sendmessage,通常都是行为不可预测的。

1.工作线程给主线程发消息使用的是SendMessage和PoseMessage函数。这两个函数的区别在于SendMessage函数是阻塞方式,而PoseMessage函数是非阻塞方式。如果不是严格要求工作线程与主线程必须同步执行,则推荐使用PoseMessage。

2.不要在线程函数体内操作MFC控件,因为每个线程都有自己的线程模块状态映射表,在一个线程中操作另一个线程中创建的MFC对象,会带来意想不到的问题。更不要在线程函数里,直接调用UpdataData()函数更新用户界面,这会导致程序直接crash。而应该通过发送消息给主线程的方式,在主线程的消息响应函数里操作控件。

3.在主线程中不要使用WaitForSingleObject和WaitForMultipleObjects两个函数等待线程退出,其原因就是有导致程序死锁的隐患,特别是线程函数里调用了SendMessage或是直接操作了MFC对象,更易出现此种现象。为解决这一问题,微软特提供了一个函数,MsgWaitForMultipleObjects。

照着网上的例子,写了在主线程中等待单个线程退出的程序:

DWORD dRet=-2;
MSG msg;
BOOL bWaitAll=FALSE;
int nWaitCount=2; //初始等待的线程数目
while (1)
{
dRet=MsgWaitForMultipleObjects(1,句柄的指 针,bWaitAll,INFINITE,QS_ALLINPUT);
if (dRet == WAIT_OBJECT_0 + 1)
{
TRACE("收到消息,函数返回值为%d \n",dRet);
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else if (dRet == WAIT_OBJECT_0 )
{
TRACE("线程退出了\n");
break;
}
}//end while
}

实际使用中,在主线程中使用WaitForMultipleObjects导致界面线程在子线程结束前失去响应,而使用MsgWaitForMultipleObjects则很好的解决了这个问题。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/nefeithu123/archive/2009/06/07/4250002.aspx

1、尽量少的使用全局变量、static变量做共享数据,尽量使用参数传递对象。被参数传递的对象,应该只包括必需的成员变量。所谓必需的成员变量,就是必定会被多线程操作的。很多人图省事,会把this指针(可能是任意一个对象指针)当作线程参数传递,致使线程内部有过多的操作权限,对this中的参数任意妄为。整个程序由一个人完成,可能会非常注意,不会出错,但只要一转手,程序就会面目全非。当两个线程同时操作一个成员变量的时候,程序就开始崩溃了,更糟的是,这种错误很难被重现。(我就在郁闷这个问题,我们是几个人,把程序编成debug版,经过数天使用,才找到错误。而找到错误只是开始,因为你要证明这个bug被修改成功了,也非常困难。)其实,线程间数据交互大多是单向的,在线程回调函数入口处,尽可能的将传入的数据备份到局部变量中(当然,用于线程间通讯的变量不能这么处理),以后只对局部变量做处理,可以很好的解决这种问题。
2、在MFC中请慎用线程。因为MFC的框架假定你的消息处理都是在主线程中完成的。首先窗口句柄是属于线程的,如果拥有窗口句柄的线程退出了,如果另一个线程处理这个窗口句柄,系统就会出现问题。而MFC为了避免这种情况的发生,使你在子线程中调用消息(窗口)处理函数时,就会不停的出Assert错误,烦都烦死你。典型的例子就时CSocket,因为CSocket是使用了一个隐藏窗口实现了假阻塞,所以不可避免的使用了消息处理函数,如果你在子线程中使用CSocket,你就可能看到assert的弹出了。
3、不要在不同的线程中同时注册COM组件。两个线程,一个注册1.ocx, 2.ocx, 3.ocx, 4.ocx; 而另一个则注册5.ocx, 6.ocx, 7.ocx, 8.ocx,结果死锁发生了,分别死在FreeLibrary和DllRegisterServer,因为这8个ocx是用MFC中做的,也可能是MFC的Bug,但DllRegisterServer却死在GetMoleFileName里,而GetMoleFileName则是个API唉!如果有过客看到,恰巧又知道其原因,请不吝赐教。
4、不要把线程搞的那么复杂。很多初学者,恨不能用上线程相关的所有的函数,这里互斥,那里等待,一会儿起线程,一会儿关线程的,比起goto语句有过之而无不及。好的多线程程序,应该是尽量少的使用线程。这句话怎么理解呐,就是说尽量统一一块数据共享区存放数据队列,工作子线程从队列中取数据,处理,再放回数据,这样才会模块化,对象化;而不是每个数据都起一个工作子线程处理,处理完了就关闭,写的时候虽然直接,等维护起来就累了。

6. VC中MFC创建了多线程,界面怎么还会有卡死现象,但程序在正确执行(可以执行出结果)

创建完线程后主线程 Sleep(time*1000+100);
当然卡死了

7. 怎么在基于对话框的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动画等.

8. mfc创建线程的三种方法

MFC中有两类线程,分别称之为工作者线程和用户界面线程。二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环。
工作者线程没有消息机制,通常用来执行后台计算和维护任务,如冗长的计算过程,打印机的后台打印等。用户界面线程一般用于处理独立于其他线程执行之外的用户输入,响应用户及系统所产生的事件和消息等。但对于Win32的API编程而言,这两种线程是没有区别的,它们都只需线程的启动地址即可启动线程来执行任务

1、WIN的API函数CreateThread

HANDLE CreateThread(
LPSECURITY_ATTRIBUTESlpThreadAttributes, // SD
DWORDdwStackSize, // initial stack size
LPTHREAD_START_ROUTINElpStartAddress, // thread function
LPVOIDlpParameter, // thread argument
DWORDdwCreationFlags, // creation option
LPDWORDlpThreadId // thread identifier
);
//lpThreadAttributes:指向SECURITY_ATTRIBUTES型态的结构的指针。在Windows 98中忽略该参数。在Windows NT中,它被设为NULL,表示使用缺省值。

dwStackSize,线程堆栈大小,一般=0,在任何情况下,Windows根据需要动态延长堆栈的大小。

lpStartAddress,指向线程函数的指针,形式:@函数名,函数名称没有限制,但是必须以下列形式声明:

DWORD WINAPI ThreadProc (LPVOID lpParam) ,格式不正确将无法调用成功。

lpParameter:向线程函数传递的参数,是一个指向结构的指针,不需传递参数时,为NULL。

dwCreationFlags :线程标志,可取值如下

(1)CREATE_SUSPENDED-----创建一个挂起的线程,

(2)0---------------------------------表示创建后立即激活。

lpThreadId:保存新线程的id。

2、MFC的全局函数AfxBeginThread

CWinThread* AfxBeginThread( AFX_THREADPROCpfnThreadProc, LPVOIDpParam, intnPriority= THREAD_PRIORITY_NORMAL, UINTnStackSize= 0, DWORDdwCreateFlags= 0, LPSECURITY_ATTRIBUTESlpSecurityAttrs= NULL );

//用于创建工作者线程 其中pfnThreadProc指向线程函数 pParam为传递给线程函数的参数

CWinThread* AfxBeginThread( CRuntimeClass*pThreadClass, intnPriority= THREAD_PRIORITY_NORMAL, UINTnStackSize= 0, DWORDdwCreateFlags= 0, LPSECURITY_ATTRIBUTESlpSecurityAttrs= NULL );

//用于创建用户界面线程 其中pThreadClass为CWinThread派生对象的RUNTIME_CLASS

3、MFC的CWinThread类的CreateThreat成员函数

BOOL CreateThread( DWORD dwCreateFlags = 0, UINT nStackSize = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );

//CWinThread类支持工作者线程和用户界面线程 可以将一个CWinThread派生类的CRUNTIMECLASS的指针作为参数传递给AfxBeginThread函数以创建一个用户界面线程 CWinThread类的CreateThread成员函数创建一个调用进程的地址空间中执行的线程

VC 6.0 创建线程的三种方法

CreateThread/ExitThread
_beginthreadex/_endthreadex
AfxBeginThread /AfxEndThread

对以上三种方式的选择:

1.在使用了MFC的程序中使用AfxBeginThread函数或者CWinThread::CreateThread函数创建线程。

2.在非MFC工程中,如果要创建多线程,建议使用_beginthreadex

3.避免使用CreateThread函数。不使用_beginthread.

4.线程内部退出函数使用与创建函数配套的函数。

9. VC++中如何用多线程

你说的是MFC吗?MFC可以用AfxBeginThread函数创建线程,可以把ThreadProc声明为类的静态成员函数,你会单线程下载页面,要在多线程下下载页面就不成问题了哈.
推荐你看看<WIN32多线程程序设计>
www.infoxa.com上有下载

10. MFC中实现多线程

MFC CThread 去看下就会啦。。等待就是一个WaitForSingleObject函数

阅读全文

与vc2013mfc多线程编程相关的资料

热点内容
各种直线命令详解 浏览:859
程序员泪奔 浏览:143
素材怎么上传到服务器 浏览:513
android百度离线地图开发 浏览:187
web可视化编程软件 浏览:288
java笔试编程题 浏览:742
win11什么时候可以装安卓 浏览:560
java不写this 浏览:999
云点播电影网php源码 浏览:95
pythonclass使用方法 浏览:226
移动加密软件去哪下载 浏览:294
php弹出alert 浏览:209
吉林文档课件加密费用 浏览:136
传感器pdf下载 浏览:289
随车拍app绑定什么设备 浏览:898
方维团购系统源码 浏览:993
linux反弹shell 浏览:159
打印机接口加密狗还能用吗 浏览:301
二板股票源码 浏览:448
度人经pdf 浏览:902