wxWidgets多线程及事件传递

前言

​ 最近忙着写项目,wxWidgets计划还有wxWidgets日志系统的拦截重定向,剩下一些比较杂的知识点,想到哪写到哪。比如进程间通信、调用外部程序后结束本程序(用于升级程序)、集成带窗口的ActiveX、创建单进程程序等,这些文档上基本都有。下面开始多线程的应用。

代码示例

​ 废话不多说,此示例演示,子线程进程业务处理完之后通知主线程,等待主线程执行完,子线程接着处理业务的过程。

​ 主要内容在主窗口文件和线程文件里面

​ 主窗口头文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/***************************************************************
* Name: blog_WidgetsMain.h
* Purpose: Defines Application Frame
* Author: ()
* Created: 2021-02-23
* Copyright: ()
* License:
**************************************************************/

#ifndef BLOG_WIDGETSMAIN_H
#define BLOG_WIDGETSMAIN_H

#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif

#include "blog_WidgetsApp.h"
enum SIGN_NUM{
SIGN_1 = 8000,
BTN1,
BTN2
};

class blog_WidgetsFrame: public wxFrame
{
public:
blog_WidgetsFrame(){}
blog_WidgetsFrame(wxFrame *frame, const wxString& title);
~blog_WidgetsFrame();
public:
wxMutex* mutex;//互斥量
wxCondition* condition;//条件变量
wxString speak;//主线程要说的话
protected:
//接收子线程发送的信号
void OnThreadEvent(wxThreadEvent& event);
//按钮1的事件,创建子线程,并启动
void OnBtnStartEvent(wxCommandEvent& event);
//按钮2的事件,通知子线程继续
void OnBtnChildrenEvent(wxCommandEvent& event);
//唤醒子线程
void SendSign();
private:
//将类加入到RTTI中,供类型转换使用,可以使用wxDynamicCast进行转换
DECLARE_DYNAMIC_CLASS(blog_WidgetsFrame);
//定义事件表
DECLARE_EVENT_TABLE()

};


#endif // BLOG_WIDGETSMAIN_H

​ 主窗口实现文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/***************************************************************
* Name: blog_WidgetsMain.cpp
* Purpose: Code for Application Frame
* Author: ()
* Created: 2021-02-23
* Copyright: ()
* License:
**************************************************************/


#include "blog_WidgetsMain.h"
#include "ChildrenThread.h"


IMPLEMENT_DYNAMIC_CLASS(blog_WidgetsFrame,wxFrame)
BEGIN_EVENT_TABLE(blog_WidgetsFrame, wxFrame)
//绑定子线程发出的信号函数
EVT_THREAD(SIGN_1,blog_WidgetsFrame::OnThreadEvent)
//绑定接收button的信号函数,这里因为wxCommandEvent是事件可以传播的,主窗口也能接收到button的信号
EVT_BUTTON(BTN1,blog_WidgetsFrame::OnBtnStartEvent)
EVT_BUTTON(BTN2,blog_WidgetsFrame::OnBtnChildrenEvent)
END_EVENT_TABLE()

blog_WidgetsFrame::blog_WidgetsFrame(wxFrame *frame, const wxString& title)
: wxFrame(frame, -1, title)
{
mutex = new wxMutex();
condition = new wxCondition(*mutex);

//增加一个按钮,点击按钮后通知子线程接着执行
wxButton* button1 = new wxButton(this,BTN1,wxT("开始"));
wxButton* button2 = new wxButton(this,BTN2,wxT("通知子线程"));
//添加到布局里面
wxBoxSizer* box = new wxBoxSizer(wxVERTICAL);
box->Add(button1,1,wxALL,0);
box->Add(button2,1,wxALL,0);
this->SetSizer(box);
}


blog_WidgetsFrame::~blog_WidgetsFrame()
{
if(condition)
{
delete condition;
condition = NULL;
}
if(mutex)
{
delete mutex;
mutex = NULL;
}
}
void blog_WidgetsFrame::OnThreadEvent(wxThreadEvent& event)
{
wxString text = event.GetString();
wxMessageBox(text,wxT("子线程"));
}

void blog_WidgetsFrame::OnBtnStartEvent(wxCommandEvent& event)
{
//建立子线程
ChildrenThread* childrenThread = new ChildrenThread(this);
//运行子线程,分离线程无需手动销毁
if(childrenThread != NULL)
{
if(childrenThread->Create()== wxTHREAD_NO_ERROR)
{
childrenThread->Run();
}
}
}
void blog_WidgetsFrame::OnBtnChildrenEvent(wxCommandEvent& event)
{
SendSign();
}



void blog_WidgetsFrame::SendSign()
{
wxMutexLocker lock(*mutex);
condition->Signal();
}

子线程头文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef CHILDRENTHREAD_H
#define CHILDRENTHREAD_H

#include <wx/wx.h>
#include "../blog_WidgetsMain.h"
class ChildrenThread: public wxThread
{
public:
ChildrenThread(wxFrame* frame);
virtual ~ChildrenThread();
virtual void* Entry();
void threadWait(wxThreadEvent& event);
protected:

private:
wxFrame* m_frame;
};

#endif // CHILDRENTHREAD_H

子线程实现文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include "ChildrenThread.h"

ChildrenThread::ChildrenThread(wxFrame* frame):wxThread(wxTHREAD_DETACHED)//分离线程
{
m_frame = frame;
}
ChildrenThread::~ChildrenThread()
{

}
void* ChildrenThread::Entry()
{
blog_WidgetsFrame* frame = wxDynamicCast(m_frame,blog_WidgetsFrame);
if(frame)
{
//获取锁
frame->mutex->Lock();
wxThreadEvent evt1(wxEVT_COMMAND_THREAD,SIGN_1);
evt1.SetString(wxT("子线程第一次执行的结果通知"));
//发送信号,并等待主线程通知
threadWait(evt1);

wxThreadEvent evt2(wxEVT_COMMAND_THREAD,SIGN_1);
evt2.SetString(wxT("子线程第二次执行的结果通知"));
//直接发送信号,不在等待主线程
frame->GetEventHandler()->QueueEvent(evt2.Clone());

//最后记着释放锁
frame->mutex->Unlock();
}
return NULL;
}
void ChildrenThread::threadWait(wxThreadEvent& event)
{
blog_WidgetsFrame* frame = wxDynamicCast(m_frame,blog_WidgetsFrame);
frame->GetEventHandler()->QueueEvent(event.Clone());
frame->condition->Wait();

}

调用文件就不贴出来了,简单的父子线程协同工作的demo完成。

结尾

​ 下一篇应该是wxWidgets的日志系统的拦截和重定向,把产生的日志全部拦截,记录到数据库中,供排查错误使用。

评论