C++ 关于MFC多线程编程的注意事项

在多线程编程中,最简单的方法,无非就是利用 AfxBeginThread  来创建一个工作线程,看一下这个函数的说明:

代码如下:

CWinThread* AFXAPI AfxBeginThread(
AFX_THREADPROC pfnThreadProc,
LPVOID pParam,
int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
);

在这个说明中,除第1和第2两个参数外,余下的参数都有默认值。所以,我们在使用的时候,是必须要指定前两个参数的。

其中 第一个参数是 要运行的函数的名称,光写函数名就可以了,不能加引号。

第二个参数,是指定 运行函数的 参数,这个参数的类型为 LPVOID 。所以要运行的函数的在传递过去后,要转化为LPVOID类型才可以。

而要运行的参数还有一个限制,那就是必须返回一个UINT类型的结果。所以要运行的函数的就有一个基本上固定的格式。

UINT RunProce(LPVOID lpParam)

在这里还需要特别说明一下,这个函数不能是实例函数,也就是函数前面是不能有 类限定符:: 的。如果是静态函数也是可以的。

在这个函数中,我们只能使用一个参数,而参数的类型只能是 LPVOID ,可以用一个结构体来封闭多个参数。

余下的问题,就不是很多了。

关于 多线程,就写到这里吧!

在多线程编程中,一个很重要的问题就是,要将线程的运行过程通知界面线程,做一些显示方面的更新。如下载线程,在适当的时候,可以更新界面,现在下载到什么进度了。等等的情况。但是在工作线程中,是不是直接操作界面线程的控件的。那怎么办呢,只能通过自定义一个消息来解决。

工作流程,就是 在自定义线程中 通过发送一个界面上的 消息,来通知界面做一些更新操作。在这个自定义消息中,有一个细节要解决,那就是自定义消息,必须要指定接收消息的控件句柄。当然你中以使用m_pApp 直接通知主框架来解决,但是这样解决似乎绕了一个很大的圈。其实解决的方法很简单,那就是直接将接收消息的控件的句柄传给自定义线程,就可以了。我们直接在线程中使用此句柄就可以解决了。

我们知道控件的基类都是 CWnd。所以我们传递一个CWnd的指针进去。当然还有一些其它的参数要一块传递进去,那就做一个结构吧

代码如下:

typedef struct{
 CString srcString;
 CString DesString;
 CWnd*    hander;
}Param;

这里我们传递了三个参数 两个字符串一个指针。

我们先造一个自定义线程函数

代码如下:

UINT RunProce(LPVOID lpParam)
{
    Param* par;
    CWnd* hander;
    par = (Param*)lpParam;
    hander = par->hander;
    myCopyDirectory(lpParam);
    CString str;
    str = "复制完成";
    hander->SendMessage(WM_USERMESSAGE,0,(LPARAM)&str);
    return 0;
}

在这个函数中,我们要运行由此函数组成的一个线程的话,就需要传递一个参数lpParam,而这个参数是由 Param 的结构体来指定。实际上是传递了三个参数进去。

代码如下:

Param* par;
par = (Param*)lpParam;

我们会用上在的强制类型转换的方法,就可以还原参数的值。根据这三个参数就  自定主的线程函数就可以运行了。那如何通知界面线程呢。看一下自定义函数里面的这一句

hander->SendMessage(WM_USERMESSAGE,0,(LPARAM)&str);

这一句中 hander 是由结构体转换而来的 接收消息的控件的句柄。然后调用这个控件的 SendMessage 方法,就可以向此控件发消息了。消息的内容由后面的参数来决定

第一个参数 WM_USERMESSAGE 这是一个消息的名称。这个名称实际上是一个数字。我们需要在 .h 文件中 指定一下如下面的格式

#define WM_USERMESSAGE 11130

后面的数字造的大一点,哈哈

第二个与第三个参数,就是这个消息传递具体的值,如果不需要传递值的话,那就直接写0吧

在这里我们想在传递参数的第三个参数上传递一个 字符串,那就是上面的写法了。

这样的话,在线程中发送消息的部分,就全部讲完了。消息发送出去了,怎么接收呢?

这真是一个重要的问题

首先,要将消息做一下映射。消息映射的目的,就是告诉程序,当出现这个消息的时候,使用哪个函数进行处理。这样的话,就首先需要一个消息映射的函数。这个消息映射的函数不是乱写,因为要传递两个参数,所以这个函数需要能够接收这两个参数。处理函数一般这样子写

LRESULT CCopyfileDlg::OnProcName(WPARAM wParam, LPARAM lParam)
他奶奶的,太神奇了。返回值只能是 LRESULT 。这个不用讨论吧,照着抄吧。函数名称后面有参数两个,这是一个实例函数。因为前面有::
两个参数一般也写成这个样子的。

函数内容,就由你的程序的功能决定了。我这里直接抄一段我自己的代码吧

LRESULT CCopyfileDlg::OnProcName(WPARAM wParam, LPARAM lParam)
{
  // TODO: 处理用户自定义消息
  CString* str = (CString*)lParam;
  SetDlgItemText(IDC_STATIC,*str);

  if(*str == "复制完成")
   {
     (CButton*)GetDlgItem(IDC_COPYBUT)->EnableWindow(true);
   }

  return 0;

}

这段程序是根据得到的传递过来的参数,在界面上显示具体的参数内容。

SetDlgItemText(IDC_STATIC,*str);  //在静态文本框中显示消息。

备注:

如果要让按钮变成灰色的,那就使用控件的 EnableWindow 方法。

这个方法,我们说,是专门的消息处理函数,那么它的声明也比较特殊。需要这么写

afx_msg LRESULT OnProcName(WPARAM wParam, LPARAM lParam);
将上面的内容放在 h文件的合理位置就可以了。

现在消息处理函数也有了。但是怎么将映射呢?

其实在 CPP文件中,有一个由 BEGIN_MESSAGE_MAP(CCopyfileDlg, CDialog) 和END_MESSAGE_MAP() 包括的区域。这个区域就是用来定义消息映射的。

将这么一句话放在他们中间,就OK了

ON_MESSAGE(WM_USERMESSAGE,OnProcName)
这么一句话,就将 WM_USERMESSAGE 与 OnProcName 与消息处理函数结合在一起了。是不是超级简单呀!

这样我们的界面线程中的消息处理部分也主做好了。

当消息发送过来后,就会通过消息映射放在对应的函数中加以处理。

以上所述就是本文的全部内容了,希望大家能够喜欢。

(0)

相关推荐

  • VC++开发中完美解决头文件相互包含问题的方法解析

    所谓超前引用是指一个类型在定义之前就被用来定义变量和声明函数. 一般情况下,C/C++要求所有的类型必须在使用前被定义,但是在一些特殊情况下,这种要求无法满足,例如,在类CMyView中保留了一个非模式对话框对象指针,该对象用于显示/修改一些信息.为了实现对话框"应用"按钮,把对话框做的修改立刻更新到view界面上,为此,需要在对话框类中需要保存view类的指针,这样定义关系就变成如下的代码: 复制代码 代码如下: #ifndef __MYVIEW_H__   #define __MY

  • C++输入输出注意事项总结

    本文总结了C++输入输出的各种注意事项,对于C++初学者或C++程序员来说都有一定的借鉴参考价值.具体总结分析如下: 一.string类: 1.cin>>string时,遇到'\n'或者空格即停止,并且'\n'或空格仍留在输入里,即只读了一个单词或什么都没读,但string类自己处理好了空字符什么的.下一次再这样读的话会跳过换行和空格; 2.读一行到string里可用getline(cin,string),这个函数一直读直到遇到了'\n',注意这里getline()不是cin的类方法,cin表

  • Linux上搭建C/C++IDE开发环境

    文/张善友 Redhat linux上面没有提供Anjuta软件包,上面提供了一个Glade应用程序界面设计工具.Linux上面使用Anjuta和Glade以及Glademm软件包可以搭建一个linux下面进行C/C++软件开发的IDE环境,可以进行GTK+/Gnome的应用程序开发. 以前开发 Linux 程序时写出好的图形化用户界面比较难.在 GIMP 工具包 (GTK)诞生之后,这件事就变得比较容易了.当Damon Chaplin 写出 GLADE 这个用于在 GTK 环境下生成图形化用户

  • 探讨:C++中函数返回引用的注意事项

    函数 返回值 和 返回引用 是不同的函数返回值时会产生一个临时变量作为函数返回值的副本,而返回引用时不会产生值的副本,既然是引用,那引用谁呢?这个问题必须清楚,否则将无法理解返回引用到底是个什么概念.以下是几种引用情况:1,引用函数的参数,当然该参数也是一个引用 复制代码 代码如下: const string &shorterString(const string &s1,const string &s2)      {             return s1.size()&l

  • c/c++语言位域注意事项分析

    复制代码 代码如下: struct weiyu{    int a:1;    int b:2;} a存放在内存的低位,在小端的机器上. 尤其要注意下面这种情况 weiyu w;w.a = 1; 这时w.a为-1,因为它是有符号的,这是个符号位.

  • C++高级程序员成长之路

    C++这门语言从诞生到今天已经经历了将近30个年头.不可否认,它的学习难度都比其它语言较高.而它的学习难度,主要来自于它的复杂性.现在C++的使用范围比以前已经少了很多,java.C#.python等语言在很多方面已经可以代替C++.但是也有很多地方是其他语言完全无法替代的,主要集中在需要运行效率比较高的行业,比如游戏.高效的服务器. 现在学习java.C#等语言的人数远远高于C++,主要是C++的入门门槛太高,可能学习了一段时间后还做不了什么东西,导致信心大受打击,进而放弃. 我想把我自己的经

  • C++开发:为什么多线程读写shared_ptr要加锁的详细介绍

    我在<Linux 多线程服务端编程:使用 muduo C++ 网络库>第 1.9 节"再论 shared_ptr 的线程安全"中写道: (shared_ptr)的引用计数本身是安全且无锁的,但对象的读写则不是,因为 shared_ptr 有两个数据成员,读写操作不能原子化.根据文档(http://www.boost.org/doc/libs/release/libs/smart_ptr/shared_ptr.htm#ThreadSafety), shared_ptr 的线程

  • 安卓应用开发通过java调用c++ jni的图文使用方法

    首先建议一个工程 HelloJni如下图: 按照默认的配置下一步,直到完成 . 如下图操作,点击windows菜单->Prefrence菜单: 弹出如下图:选择Andriod ->NDK: 配置完成以后,点击工程属性菜单: 做这一步的目的是,增加对c++代码的支持,他会自动生成一些东西,你会看到多一个jni的文件夹. 这个名字可以默认,就用工程的名字,实际上就是产生的c++代码生成.so文件的名称(windows上的dll文件). 完成以后.可以看代码,生成一个HelloJni的.cpp文件.

  • C++ 关于MFC多线程编程的注意事项

    在多线程编程中,最简单的方法,无非就是利用 AfxBeginThread  来创建一个工作线程,看一下这个函数的说明: 复制代码 代码如下: CWinThread* AFXAPI AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_AT

  • VC多线程编程详解

    本文实例讲述了VC多线程编程概念与技巧,分享给大家供大家参考.具体分析如下: 一.多线程编程要点 线程是进程的一条执行路径,它包含独立的堆栈和CPU寄存器状态,每个线程共享所有的进程资源,包括打开的文件.信号标识及动态分配的内存等.一个进程内的所有线程使用同一个地址空间,而这些线程的执行由系统调度程序控制,调度程序决定哪个线程可执行以及什么时候执行线程.线程有优先级别,优先权较低的线程必须等到优先权较高的线程执行完后再执行.在多处理器的机器上,调度程序可将多个线程放到不同的处理器上去运行,这样可

  • C++11中多线程编程-std::async的深入讲解

    前言 C++11中提供了异步线程接口std::async,std::async是异步编程的高级封装,相对于直接使用std::thread,std::async的优势在于: 1.std::async会自动创建线程去调用线程函数,相对于低层次的std::thread,使用起来非常方便: 2.std::async返回std::future对象,通过返回的std::future对象我们可以非常方便的获取到线程函数的返回结果: 3.std::async提供了线程的创建策略,可以指定同步或者异步的方式去创建

  • java多线程编程必备volatile与synchronized深入理解

    目录 Volatile概述 Synchronized概述 Volatile与Synchronized的区别 使用场景 1 Volatile的使用场景 2 Synchronized的使用场景 注意事项 相关面试问题 Volatile概述 Volatile是Java中的一种轻量级同步机制,用于保证变量的可见性和禁止指令重排.当一个变量被声明为Volatile类型时,任何修改该变量的操作都会立即被所有线程看到.也就是说,Volatile修饰的变量在每次修改时都会强制将修改刷新到主内存中,具有很好的可见

  • linux下c语言的多线程编程

    我们在写linux的服务的时候,经常会用到linux的多线程技术以提高程序性能 多线程的一些小知识: 一个应用程序可以启动若干个线程. 线程(Lightweight Process,LWP),是程序执行的最小单元. 一般一个最简单的程序最少会有一个线程,就是程序本身,也就是主函数(单线程的进程可以简单的认为只有一个线程的进程) 一个线程阻塞并不会影响到另外一个线程. 多线程的进程可以尽可能的利用系统CPU资源. 1创建线程 先上一段在一个进程中创建一个线程的简单的代码,然后慢慢深入. #incl

  • linux下的C\C++多进程多线程编程实例详解

    linux下的C\C++多进程多线程编程实例详解 1.多进程编程 #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int main() { pid_t child_pid; /* 创建一个子进程 */ child_pid = fork(); if(child_pid == 0) { printf("child pid\n"); exit(0); } else { print

  • Java多线程编程小实例模拟停车场系统

    下面分享的是一个Java多线程模拟停车场系统的小实例(Java的应用还是很广泛的,哈哈),具体代码如下: Park类 public class Park { boolean []park=new boolean[3]; public boolean equals() { return true; } } Car: public class Car { private String number; private int position=0; public Car(String number)

  • Java多线程编程安全退出线程方法介绍

    线程停止 Thread提供了一个stop()方法,但是stop()方法是一个被废弃的方法.为什么stop()方法被废弃而不被使用呢?原因是stop()方法太过于暴力,会强行把执行一半的线程终止.这样会就不会保证线程的资源正确释放,通常是没有给与线程完成资源释放工作的机会,因此会导致程序工作在不确定的状态下 那我们该使用什么来停止线程呢 Thread.interrupt(),我们可以用他来停止线程,他是安全的,可是使用他的时候并不会真的停止了线程,只是会给线程打上了一个记号,至于这个记号有什么用呢

  • Java多线程编程实现socket通信示例代码

    流传于网络上有关Java多线程通信的编程实例有很多,这一篇还算比较不错,代码可用.下面看看具体内容. TCP是Tranfer Control Protocol的 简称,是一种面向连接的保证可靠传输的协议.通过TCP协议传输,得到的是一个顺序的无差错的数据流.发送方和接收方的成对的两个socket之间必须建 立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以

  • java多线程编程学习(线程间通信)

    一.概要 线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体,线程间的通信就是成为整体的必用方案之一.可以说,使线程进行通信后,系统之间的交互性会更强大,在大大提高cpu利用率的同时还会使程序员对各线程任务在处理过程中进行有效的把控和监督. 二.等待/通知机制 1."wait/notify"机制:等待/通知机制,wait使线程暂停运行,而notify 使暂停的线程继续运行.用一个厨师和服务员的交互来说明: (1) 服务员取到菜的时间取决于厨师,所以服务员就有&

随机推荐