精华内容
下载资源
问答
  • C++ 事件(event)使用总结

    千次阅读 2020-09-03 13:29:13
    事件最常用在多线程同步互斥机制。 常用的函数有: 1、CreateEvent 创建事件。 函数原型如下所示,一共四个参数: HANDLE CreateEvent(  LPSECURITY_ATTRIBUTES lpEventAttributes, // SECURITY_ATTRIBUTES...

      事件最常用在多线程同步互斥机制。

     常用的函数有:

     1、CreateEvent 创建事件。

    函数原型如下所示,一共四个参数:

    HANDLE CreateEvent(

     LPSECURITY_ATTRIBUTES lpEventAttributes, // SECURITY_ATTRIBUTES结构指针,可为NULL
     BOOL bManualReset,     // 手动/自动
                                         // TRUE:表示手动,在WaitForSingleObject后必须手动调用ResetEvent清除信号
                                        // FALSE:表示自动,在WaitForSingleObject后,系统自动清除事件信号
     BOOL bInitialState,        //初始状态,FALSE为无信号,TRUE为有信号
     LPCTSTR lpName         //事件的名称
        );

    2、SetEvent:设置为激活触发状态。

    3、ResetEvent:设置为未激活触发状态。

    4、WaitForSingleObject:检测信号,如果未激活,代码就会处于挂起状态,不再往下执行。

    下面是多线程同步的示例:

    #include <tchar.h> 
    #include <iostream>
    #include <wtypes.h>
    using namespace std;
    
    DWORD WINAPI ThreadProc(LPVOID lpParam);
    DWORD WINAPI ThreadProc2(LPVOID lpParam);
    DWORD g_dwThreadID;
    DWORD g_dwThreadID2;
    UINT g_nTickets = 300;  
    HANDLE g_hEvent1 = NULL;
    HANDLE g_hEvent2 = NULL;
    CRITICAL_SECTION g_cs;
    int ThreadCout = 0;
    
    int main(int argc, _TCHAR* argv[])
    {
    	cout << "Main thread is running." << endl;
    	InitializeCriticalSection(&g_cs);//初始化临界区
    	HANDLE hHandle = CreateThread(NULL, 0, ThreadProc, NULL, 0, &g_dwThreadID);
    	ThreadCout++;
    	HANDLE hHandle2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, &g_dwThreadID2);
    	ThreadCout++;
    	g_hEvent1 = CreateEvent(NULL, FALSE, TRUE, NULL);  //备注5:g_hEvent1 = CreateEvent(NULL, TRUE,  TRUE, NULL);
    	g_hEvent2 = CreateEvent(NULL, FALSE, TRUE, NULL);  //备注5:g_hEvent2 = CreateEvent(NULL, TRUE,  TRUE, NULL);
    	ResetEvent(g_hEvent1);
    	ResetEvent(g_hEvent2);
    	SetEvent(g_hEvent1);
    	while (TRUE)
    	{
    		EnterCriticalSection(&g_cs);
    		int nCount = ThreadCout;
    		LeaveCriticalSection(&g_cs);
    		if (nCount == 0)
    		{
    			cout << "Main break" << endl;
    			break;
    		}
    	}
    	Sleep(1000);    //备注4
    	CloseHandle(hHandle);
    	CloseHandle(hHandle2);
    	DeleteCriticalSection(&g_cs);
    	cout << "Main End " << endl;
    	system("pause");
    	return 0;
    }
    
    DWORD WINAPI ThreadProc(LPVOID lpParam)
    {
    	while (TRUE)
    	{
    		WaitForSingleObject(g_hEvent1, INFINITE);
    		cout << "线程1:" << g_dwThreadID << " thread is running." << endl;
    		EnterCriticalSection(&g_cs);
    		int temp = g_nTickets;
    		LeaveCriticalSection(&g_cs);
    		cout << "线程1:" << g_dwThreadID << " thread is temp." << endl;
    		if (temp > 0)
    		{
    			Sleep(100);  //Sleep(1000)   
    			cout << "线程1:" << g_dwThreadID << " sell ticket : " << temp << endl;
    			EnterCriticalSection(&g_cs);
    			g_nTickets--;
    			LeaveCriticalSection(&g_cs);
    			SetEvent(g_hEvent2);
    		}
    		else
    		{
    			cout << "线程1 break" << endl;
    			SetEvent(g_hEvent2);//没有这个ThreadProc2不能终止   
    			break;
    		}
    	}
    	EnterCriticalSection(&g_cs);
    	ThreadCout--;
    	LeaveCriticalSection(&g_cs);
    	cout << "线程1 end" << endl;
    	return 0;
    }
    
    DWORD WINAPI ThreadProc2(LPVOID lpParam)
    {
    	while (TRUE)
    	{
    		WaitForSingleObject(g_hEvent2, INFINITE);
    		cout << "线程2: " << g_dwThreadID2 << " thread is running." << endl;
    		EnterCriticalSection(&g_cs);
    		int temp = g_nTickets;
    		LeaveCriticalSection(&g_cs);
    		if (temp > 0)
    		{
    			Sleep(100);  //Sleep(1000)   //备注2
    			cout << "线程2:" << g_dwThreadID2 << " sell ticket : " << temp << endl;
    			EnterCriticalSection(&g_cs);
    			g_nTickets--;
    			LeaveCriticalSection(&g_cs);
    			SetEvent(g_hEvent1);			
    		}
    		else
    		{
    			cout << "线程2 break" << endl;			
    			SetEvent(g_hEvent1);//同样的问题,没有这个ThreadProc不能终止
    			break;
    		}
    	}
    	EnterCriticalSection(&g_cs);
    	ThreadCout--;
    	LeaveCriticalSection(&g_cs);
    	cout << "线程2 end" << endl;
    	return 0;
    }

    执行结果如下图:

    展开全文
  • C++事件(event)

    2013-09-22 17:29:48
    C++事件相关介绍,对C++程序开发很有帮助。
  • 主要为大家详细介绍了C++事件驱动型银行排队模拟,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • UE4 C++ 事件

    2021-02-17 11:12:53
    虽然任意类均可绑定事件,但只有声明事件的类可以调用事件 的 Broadcast、IsBound 和 Clear 函数。这意味着事件对象可在公共接口中公开,而无需让外部类访问这些敏感度函数。事件使用情况有:在纯抽象类中包含回调、...

    2021-2-17

    官方文档

    事件

    事件与 组播委托 十分相似。虽然任意类均可绑定事件,但只有声明事件的类可以调用事件 的 Broadcast、IsBound 和 Clear 函数。这意味着事件对象可在公共接口中公开,而无需让外部类访问这些敏感度函数。事件使用情况有:在纯抽象类中包含回调、限制外部类调用 Broadcast、IsBound 和 Clear 函数。
    只有声明事件的类可以调用事件
    只有声明事件的类可以调用事件
    只有声明事件的类可以调用事件

    声明事件

    事件的声明和 组播委托声明 方式几乎相同,唯一的区别是它们使用事件特有的宏变体。

    声明宏 描述

    DECLARE_EVENT( OwningType, EventName ) 创建一个事件。

    DECLARE_EVENT_OneParam( OwningType, EventName, Param1Type ) 创建带一个参数的事件。

    DECLARE_EVENT_TwoParams( OwningType, EventName, Param1Type, Param2Type ) 创建带两个参数的事件。

    DECLARE_EVENT_Params( OwningType, EventName, Param1Type, Param2Type, …) 创建带 N 个参数的事件。

    注:DECLARE_EVENT 宏的首个参数是"拥有"此事件的类,因此可调用 Broadcast() 函数。

    绑定事件

    事件绑定与 组播委托绑定 方式相同。

    事件执行

    事件允许附带多个函数委托,然后调用事件的 Broadcast() 函数将它们一次性全部执行。事件签名不允许使用返回值。对于事件而言,只有定义事件的类才能调用 Broadcast() 函数。

    即使不存在绑定,在事件上调用 Broadcast() 也是安全操作。唯一需要注意的情况是使用事件初始化输出变量,通常不建议执行此操作。

    调用 Broadcast() 函数时,被绑定函数的执行顺序尚未定义。有可能不按照函数的添加顺序执行。

    Broadcast() 将此事件广播到所有绑定对象,已失效的对象除外。

    例:
    测试函数(属于待绑定的对象)的实现仅打印函数名
    在这里插入图片描述
    声明,一般在类的定义里面,在制造委托的类中声明
    在这里插入图片描述
    在这里插入图片描述
    绑定及调用,此处写在同一个函数内
    在这里插入图片描述
    在这里插入图片描述
    其他类调用事件
    在这里插入图片描述

    展开全文
  • C++开发过程由于这样那样的原因,可以会出现点击菜单、右键菜单无响应的问题,或者点击A菜单,但是响应的却是B菜单。遇到上述问题时,你可以从下面几个方面分析,一般都可以解决问题。下面从四个方面来解决问题: ...
  • C++ 事件编程

    千次阅读 2017-09-05 10:56:45
    ++ 事件编程 ...在微软 .NET 框架中可以定义托管类事件并用委托和 += 操作符...Visual C++ .NET 具备所谓统一事件模型(Unified Event Model),它可以像托管类一样实现本机事件(用 __event 关键字),但是由于

    ++ 事件编程

    在微软 .NET 框架中可以定义托管类事件并用委托和 += 操作符处理这些事件。这种机制似乎很有用,那么在本机 C++ 中有没有办法做同样的事情?

    Several Readers
     确实如此!Visual C++ .NET 具备所谓统一事件模型(Unified Event Model),它可以像托管类一样实现本机事件(用 __event 关键字),但是由于本机事件存在一些不明显的技术问题,而微软的老大不打算解决这些问题,所以他们要我正式奉劝你不要使用它们。那么这是不是就是说 C++ 程序员与事件无缘了呢?当然不是!可以通过别的方法实现。本文我将向你展示如何轻松实现自己漂亮的事件系统。
      但是在动手之前,让我先大体上介绍一下事件和事件编程。它是个重要的主题,当今对事件没有坚实的理解,你是无法编写程序的——什么是事件以及什么时候使用事件。
      成功的编程完全在于对复杂性的掌控。很久以前,函数被称为“子程序”(我知道,我这样说证明我已经老了!)管理复杂性的主要方式之一是自顶向下的编程模式。高层实现类似“宇宙模型”,然后将它划分为更小的任务如:“银河系模型”以及“太阳系模型”等等,直到任务被划分为可以用单个函数实现为止。目前自顶向下的编程模型仍被用于过程化的任务实现当中,但它不适用于发生顺序不确定的实时事件响应系统。经典的例子便是 GUI,程序必须响应用户的某些行为,比如按键或是鼠标移动。实际上,事件编程很到程度上源于图形用户界面的出现。
      在自顶向下的模型中,在顶部的高级部分对低级的实现各种不同任务的函数——如 DoThis,DoThat 进行食物链式的调用。但不久以后,低层部分需要回调(talk back),在 Windows 中,可以调用 Rectangle 或 Ellipse 绘制一个矩形或椭圆,但最终 Windows 需要调用你的应用程序来画窗口。但应用程序都还不存在,它仍然处于被调用度状态!那么 Windows 如何知道要调用哪个函数呢?这就是事件用处之所在。


    Figure 1 自顶向下和自底向上

      在每个 Windows 程序的核心——不论是直接用 C 语言编写的还是使用 MFC 或 .NET 框架类编写——都是一个处理消息的窗口过程,这些消息如:WM_PAINT, WM_SETFOCUS 和 WM_ACTIVATE。你(MFC 或 .NET)实现窗口过程并将它传递给 Windows。到了该画窗口,改变输入焦点以及激活窗口的时候,Windows 用相应的消息代码调用你的过程。这个消息就是事件。窗口过程就是事件处理器。
      如果过程化编程是自顶向下的,事件编程是自底向上。在典型的软件系统中,函数的调用流是从较高级部分到低级部分进行的;而事件是以相反的方向过滤的,如 Figure 1 所示。当然,在现实的开发中层次关系并不总是这么清晰。许多软件系统看起来更像 Figure 2 所示的情况:


    Figure 2 混合模型

      那么到底什么叫事件?其实,事件就是回调。而不是在编译时就已知名字的函数调用,组件调用在运行时调用你提供的函数。在 Windows 中,它是一个窗口过程。在 .NET 框架中,它叫做委托。不管术语怎么叫,事件提供了一种软件组件调用函数的方式,这种调用方式直到运行时才知道要调用什么函数。回调被称为事件处理器。发生或触发一个事件意味调用这个事件处理器。为此,事件接收部分首先得给事件源提供一个事件处理器的指针,这个过程叫注册。
      通常在以下几种场合下我们要使用事件:

    • 通知客户机实际的事件:用户按下某个按键;午夜时钟敲响;风扇停止工作造成 CPU 烧毁;
    • 当拷贝文件或搜索巨型数据库时,报告耗时操作的过程,组件可以周期性地触发某个事件以报告已拷贝了多少文件或已搜索了多少记录;
    • 如果你使用 IWebBrowser2 在自己的应用程序中宿主 IE,报告所发生的重要的或引起注意的事件,浏览器会在导航到某个新页面之前或之后通知你,或者在创建一个新窗口时通知你。
    • 调用应用程序提供的算法:C 运行时库函数 qsort 排序对象数组,但你必须提供比较函数。借助许多 STL 容器也能实现同样的诀窍.大多数程序员不会调用 qsort 回调某个事件,但你没有理由不考虑那种方式。它是“时间比较”事件。

      一些读者问:异常和事件之间有什么差别?主要差别是:异常表示不应该发生的意外情况。例如,你的程序运行耗尽内存,或者遇到被零除。这些都是你并不希望发生的异常情况,并且一旦出现这些情况,你的程序必须要做出相应的处理。另一方面,事件则是每天常规操作的部分并且完全是预期的。用户移动鼠标或按下某个键。浏览器导航到一个新页面。从控制流的角度看,事件是一次函数调用,而异常则是堆栈的突然跳跃,用展开的语义销毁丢失的对象。
      有关事件常见的概念误解是认为它们是异步的。虽然事件常常被用于处理用户输入和其它异步发生的行为 ,但事件本身是以同步方式发生的。触发一个事件与调用该事件处理器是同一件事情。用伪码表示就像如下的代码段:

    // raise Foo event
                for (/* each registered object */) {
                obj->FooHandler(/* args */);
                }

      控制立即传到事件处理器,并且不会返回,除非处理完成。某些系统提供某种以异步触发事件的方式,例如,在 Windows 中,你可以用 PostMessage 代替 SendMessage。控制会从 PostMessage 立即返回,该消息是后来才处理的。但是 .NET 框架中的事件以及我在这里讨论的事件是在触发时被立即处理的。当然,你总是可以触发来自运行在单独的线程中的消息代码事件,或者使用异步委托调用在线程池中执行每个事件处理器,在这种情况下,相对于主线程来说,事件是异步发生的。
      Windows 处理事件的方式完全是通过窗口过程以及一成不变的 WPARAM/LPARAM 参数,按照现代编程标准来说,简陋而粗糙。即便是在今天,每个 Windows 程序仍然在使用这种机制。有些程序员为了传递事件,甚至创建 不可见窗口。窗口过程并不是真正意义上的事件机制,因为在 Winodows 中每个窗口只允许有一个窗口过程,虽然也可以链接多个过程,比如每个过程都调用其前面的过程,也就是众所周知的子类化过程。在真正的事件系统中,相同的事件可以不分等级地注册多个接收者。
      在 .NET 框架中,事件是很成熟的机制。任何对象都可以定义事件,并且多个对象可以侦听这些事件。.NET 中的事件使用委托来实现,委托是 .NET 中的术语,它实际上就是以前说所的回调。最重要的是,委托是类型安全的。不再使用 void* 或者 WPARAM/LPARAM。
      为了用托管扩展定义一个事件,你得用 __event 关键字。例如,Windows::Forms 中的 Button 类有一个 Click 事件:

    // in Button class
                public:
                __event EventHandler* Click;

    这里 EventHandler 是某个函数的委托,该函数带有参数:Object (也就是 sender) 和 EventArgs:

    public __delegate void EventHandler(
                Object* sender,
                EventArgs* e
                );

      为了接收事件,你必须用正确的签名实现处理器成员函数并创建一个委托来包装该函数,然后调用事件的 += 操作符注册你的处理器/委托。对于上面的 Click 事件,代码应该像这样:

    // event handler
                void CMyForm::OnAbort(Object* sender, EventArgs *e)
                {
                ...
                }
                // register my handler
                m_abortButton->Click += new EventHandler(this, OnAbort);

      注意该处理器函数必须具备由委托定义的签名。这是托管扩展的基本原则。但是你的问题涉及的不是托管事件,你问的是本机事件——如何实现本机 C++ 事件?C++ 本身没有内建的事件机制,那么该怎么实现呢?你可以用 typedef 来定义一个回调并让客户机来提供这个回调,这种做法有些类似 qsort——但那样太老土了。更不用说处理多个事件时的繁琐。相对于静态外部函数来说,用成员函数作为事件处理器是最丑陋的做法。
      一种比较好的方法是创建一个定义事件的接口。那是 COM 的做法。但你不需要用 C++ 编写沉重的 COM 代码;你可以用一个简单的类。我写了一个类来做示范:CPrimeCalculator;这个类的功能是查找素数。代码如 Figure 3 所示。CPrimeCalculator::FindPrimes(n) 查找开始的 n 个素数。其工作原理是这样的,CPrimeCalculator 触发两种事件:Progress 事件和 Done 事件。这些事件都定义在 IPrimeEvents 接口中。IPrimeEvents 接口不是 .NET 和 COM 意义上的接口;它是一个纯粹的 C++ 抽象基类,它为每个事件处理器定义
    签名(参数和返回类型)。处理 CPrimeCalculator 的客户机必须实现 IPrimeEvents,然后调用 CPrimeCalculator::Register 来注册它们的恶接口。CPrimeCalculator 将对象/接口添加到其内部列表(list)中。由于它会对每个整数进行素数检查,CPrimeCalculator 则周期性地报告到目前为止找到了多少个素数:

    // in CPrimeCalculator::FindPrimes
                for (UINT p=2; p<max; p++) {
                // figure out if p is prime
                if (/* every now and then */)
                NotifyProgress(GetNumberOfPrimes());
                ...
                }
                NotifyDone();

      CPrimeCalculator 调用内部辅助函数 NotifyProgress 和 NotifyDone 来触发事件。这些函数遍历客户机对象列表,为每个客户机调用相应的事件处理器。代码如下:

    void CPrimeCalculator::NotifyProgress(UINT nFound)
                {
                list<IPrimeEvents*>::iterator it;
                for (it=m_clients.begin(); it!=m_clients.end(); it++) {
                (*it)->OnProgress(nFound);
                }
                }

    如果你对 STL 不熟悉,去看看有关迭代器反引用操作符的内容,它返回当前指向的对象,上面代码段中,for 循环里的代码等同于:

    IPrimeEvents* obj = *it;
                obj->OnProgress(nFound);

      触发 Done 事件的 NotifyDone 函数做法类似,它没有参数,如 Figure 3 所示。你也许觉得 Done 事件是多余的,因为当 FindPrimes 返回控制时,客户机已经知道 CPrimeCalculator 完成了工作。没错——但有一种情况除外,那就是多个客户机注册接收的事件,并且调用 CPrimeCalculator::FindPrimes 的对象可能不是同一个。Figure 4 是我的测试程序 PrimeCalc。该程序为素数事件实现了两个不同的事件处理器。第一个处理器是主对话框本身,CMyDlg,它利用多继承实现 IPrimeEvents。该对话框处理 OnProgress 和 OnDone,并在对话窗口显示进度,完成后发出蜂鸣声。其它的事件处理器,如 CTracePrimeEvents 也实现了 IPrimeEvents,这个实现显示诊断(TRACE)流中的信息。如 Figure 6 所示,在我的 TraceWin 程序(参见 2004 年三月的专栏)中显示的范例输出。我写的 CTracePrimeEvents 展示了多个客户机如何注册相同的事件。


    Figure 5 运行中的 PrimeCalc

      从使用 CPrimeCalculator 来编写应用的程序员角度看,处理事件简单而直白。从 IPrimeEvents 派生,实现处理器函数,然后调用 Register。从编写触发事件的类的程序员看来,这个过程有些冗长乏味。首先你得定义事件接口。这并没有什么不好。但接着你得编写 Register 和 Unregister 函数,每个 Foo 事件都得有一个相应的 NotifyFoo 函数。如果有 15 个事件的话,那就十分令人不爽了,尤其是每个 NotifyFoo 函数的模式都相同:

    void CMyClass::NotifyFoo(/* args */)
                {
                list<IPrimeEvents*>::iterator it;
                for (it=m_clients.begin(); it!=m_clients.end(); it++) {
                (*it)->OnFoo(/* args */);
                }
                }


    Figure 6 PrimeCalc 在 TraceWin 中的输出

      NotifyFoo 迭代客户机列表,为每个注册的客户机调用相应的 OnFoo 处理器,并传递任何需要的参数。有没有什么方法实现这个一般过程,比如用宏或者模板来封装这种繁琐而固定的样板代码,将自己从重复性劳动中解放出来呢?实际上是有的。下个月的专栏文章我们将讨论这个问题。记住在同一时间,同一频道,咱们再见——顺祝编程愉快!

    展开全文
  • c++事件总线简单实现

    千次阅读 2019-03-16 19:02:19
    事件总线2. 任意类型参数3. 注册机制4. 线程处理5. BOOST库链接时提示找不到“libxxx”6. multimap用法7.事件总线简单实现 1. 事件总线 用于多线程操作,降低库与库之间的耦合,提高执行效率。 2. 任意类型参数 当...

    1. 事件总线

    用于多线程操作,降低库与库之间的耦合,提高执行效率。

    2. 任意类型参数

    当你需要一个可变的类型时,有三种可能的解决方案:

    1. 无限制的类型,如 void*. 这种方法不可能是类型安全的,应该象逃避灾难一样避免它。
    2. 可变的类型,即支持多种类型的存储和获取的类型。
    3. 支持转换的类型,如字符串类型与整数类型之间的转换。

    解决方法:使用boost::Any

    boost::Any的一个重要特性是,它提供了存储不同类型的对象到标准库容器中的能力。它也是一种可变数据类型,这正是C++标准库非常需要而又缺乏的。

    用法
    any 只允许你在知道类型的前提下访问它的值:

    • 头文件 <boost/any.hpp>

    • 模板函数 any_cast:

        template<typename ValueType>  ValueType any_cast(const any& operand);
        any_cast 让你访问any中存放的值。参数为需要取回值的 any 对象。
        如果类型 ValueType 与所存值不符,any 抛出一个 bad_any_cast 异常。
        请注意,这个语法有点象 dynamic_cast.
        
        template<typename ValueType>  const ValueType* any_cast(const any* operand);
        any_cast 的一个重载,接受一个指向 any 的指针,并返回一个指向所存值的const指针。
        如果 any 中的类型不是 ValueType, 则返回一个空指针。
      
        template<typename ValueType>  ValueType* any_cast(any* operand);
        any_cast 的另一个重载,与前一个版本相似
      

    3. 注册机制

    4. 线程处理

    使用boost::thread:

    class HelloWorld
    {
    public:
     	void hello(const std::string& str)
     	{
            std::cout<<str;
    	}; 
    }
    
    int main(int argc, char* argv[])
    { 
     	HelloWorld obj;
    	boost::function f =  
    		boost::bind(&HelloWorld::hello,&obj,"Hello world");
     	boost::thread thrd(f) ;
     	thrd.join();
     	return 0;
    }
    

    线程局部存储:

    Boost线程库提供了智能指针boost::thread_specific_ptr来访问本地存储线程。每一个线程第一次使用这个智能指针的实例时,它的初值是NULL,所以必须要先检查这个它的只是否为空,并且为它赋值。Boost线程库保证本地存储线程中保存的数据会在线程结束后被清除。

    #include <boost/thread/thread.hpp>
    #include <boost/thread/mutex.hpp>
    #include <boost/thread/tss.hpp>
    #include <iostream>
     
    boost::mutex io_mutex;
    boost::thread_specific_ptr<int> ptr;//线程局部变量
     
    struct count
    {
    	count(int id) : id(id) { }
     
    	void operator()()
    	{
    		if (ptr.get() == 0)//初始化
    			ptr.reset(new int(0));
     
    		for (int i = 0; i < 10; ++i)
    		{
    			(*ptr)++;
    			boost::mutex::scoped_lock lock(io_mutex);
    			std::cout << id << ": "	<< *ptr << std::endl;
    		}
    	}
     
    	int id;
    };
     
    int main(int argc, char* argv[])
    {
    	boost::thread thrd1(count(1));
    	boost::thread thrd2(count(2));
    	thrd1.join();
    	thrd2.join();
    	return 0;
    }
    

    5. BOOST库链接时提示找不到“libxxx”

    编译BOOST库时,可以生成动态库或静态库,BOOST默认使用静态库链接,而且可以自动链接,但是用动态库时,需要加入宏:BOOST_ALL_DYN_LINK

    bjam stage –toolset=msvc-10.0–without-python 
    stagedir="D:/SDK/boost_1.60/vs2010" link=shared 
    runtime-link=shared threading=multi debug release
    

    所以推荐,使用静态库链接BOOST

    6. multimap用法

    插入用insert(make_pair(K,V))

    找到所有以“mk”为键的值

    RetRange range = _eventMap.equal_range(“mk”);
    for (constItr itr = range.first; itr != range.second; ++itr)
    {
    	...
    }
    

    删除:

    iterator  erase (const_iterator position);//删除某个位置的元素
    size_type erase (const key_type& k);//删除所有以K为键的元素
    iterator  erase (const_iterator first, const_iterator last);
    

    7.事件总线简单实现

    .h

    #include <string>
    #include <map>
    #include <vector>
    #include <boost/function.hpp>
    #include <boost/any.hpp>
    #include "SingleApp.h"
    
    
    /* 事件*/
    class IEvent
    {
    public:
    	enum EventType{
    		type_async =0,
    		type_sync,
    	};
    
    public:
    	IEvent(const int & id, int pri=127, EventType type= type_async);
    	IEvent(const IEvent & other);
    	IEvent & operator=(const IEvent & other);
    	bool operator ==(const IEvent & other)const;
    	bool operator < (const IEvent & other)const;
    
    private:
    	int _id;
    	int _priority;
    	EventType _type;
    };
    
    
    //处理仿函数
    struct IHandler
    {
    	boost::any _param;
    };
    //处理的仿函数定义
    typedef boost::function<void(boost::any)> Func;
    typedef std::multimap<IEvent, Func > HandlerMap;	//事件地图
    typedef HandlerMap::const_iterator constItr;
    typedef std::pair<constItr,constItr> RetRange;	//查找结果
    
    
    /* 事件总线*/
    class EventBus: public SingleApp<EventBus>
    {
    public:
    	EventBus(void);
    	~EventBus(void);
    
    public:
    
    	/************************************************************************/
    	/* 订阅事件
    		e:事件类型
    		Func:事件的处理函数,用boost::bind(&X::f, this, _1)
    	*/
    	/************************************************************************/
    	void Subscribe(const IEvent & e, Func & handler);
    
    	/************************************************************************/
    	/*  Post事件
    		e:事件
    		IHandler:参数
    	*/
    	/************************************************************************/
    	void Post(const IEvent & e, const IHandler & param);
    
    	/************************************************************************/
    	/* 取消订阅事件
    	*/
    	/************************************************************************/
    	void UnSubscribe(const IEvent & e);
    
    private:
    	HandlerMap _eventMap;
    };
    

    .cpp

    #include "EventBus.h"
    #include <boost/bind.hpp>
    #include <boost/thread/thread.hpp>
    
    
    IEvent::IEvent( const int & id, int pri/*=127*/, EventType type/*= type_async*/ )
    {
    	_id = id;
    	_priority = pri;
    	_type = type;
    }
    
    IEvent::IEvent( const IEvent & other )
    {
    	if (this == & other)
    	{
    		return;
    	}
    	else
    	{
    		this->_id = other._id; 
    		this->_priority = other._priority;
    		this->_type = other._type;
    	}
    }
    
    IEvent & IEvent::operator=( const IEvent & other )
    {
    	if (this == & other)
    	{
    		return *this;
    	}
    
    	this->_id = other._id; 
    	this->_priority = other._priority;
    	this->_type = other._type;
    	return *this;
    }
    
    
    bool IEvent::operator==( const IEvent & other ) const
    {
    	if (this->_id == other._id && 
    		this->_priority== other._priority &&
    		this->_type == other._type)
    	{
    		return true;
    	}
    	return false;
    }
    
    bool IEvent::operator<( const IEvent & other ) const
    {
    	if (this->_id < other._id )
    	{
    		return true;
    	}
    	return false;
    }
    
    EventBus::EventBus(void)
    {
    
    }
    
    EventBus::~EventBus(void)
    {
    }
    
    void EventBus::Subscribe(const IEvent & e, Func & handler )
    {
    	_eventMap.insert(std::make_pair(e,handler));
    }
    
    void EventBus::Post( const IEvent & e, const IHandler & param )
    {
    	RetRange range = _eventMap.equal_range(e);
    	for (constItr itr = range.first; itr != range.second; ++itr)
    	{
    		Func f = itr->second;
    		boost::thread thread(f, param._param);
    	}
    }
    
    void EventBus::UnSubscribe( const IEvent & e )
    {
    	_eventMap.erase(e);
    }
    

    参考:

    1. my coding.net
    2. 定义
    3. boost.any实现任意类型存储
    4. 基于Boost 的线程安全队列
    5. boost提供的几种lock-free方案以及std::atomic实现无锁队列
    6. boost::thread的六种使用方法总结
    7. 理解线程局部存储区
    8. 每天进步一点点——Linux中的线程局部存储(一)
    9. boost线程局部存储
    10. STL里的multimap使用简介
    11. http://www.cplusplus.com/reference/map/multimap/multimap/
    12. 事件总线(Event Bus)知多少
    展开全文
  • 主要介绍了C++事件处理中__event与__raise关键字的用法,是C++入门学习中的基础知识,需要的朋友可以参考下
  • __hook __hook将处理程序方法与事件关联。 语法 long __hook( &SourceClass::EventMethod, ...本机 C++ 事件:SourceClass 是事件源类,EventMethod 是事件。 COM 事件:SourceClass 是事件源接口,
  • C++事件管理

    2016-12-22 14:05:07
    C++ 事件回调机制的几种实现方式 采用委托方式 1、duilib中的CEventSource。以下代码摘自duilib,并且有一点改动。 3、msvc支持的__event 转载于 ...
  • C++ 事件实现机制

    千次阅读 2018-11-27 13:59:26
    https://www.cnblogs.com/munetiey/articles/6518537.html   http://www.cnblogs.com/bastard/archive/2012/01/10/2318417.html
  • eventpp是一个 C++ 事件库,它提供的工具允许应用程序组件通过调度事件并监听它们来相互通信。使用eventpp,您可以非常轻松地实现信号/插槽机制或观察者模式。 特性 支持同步事件调度和异步事件队列。 可配置和可...
  • C++事件处理[汇编].pdf

    2021-10-11 01:00:35
    C++事件处理[汇编].pdf
  • C++事件SetEvent,ResetEvent的使用

    千次阅读 2019-04-09 22:13:15
    创建事件: HANDLE CreateEvent(  LPSECURITY_ATTRIBUTES lpEventAttributes, // SECURITY_ATTRIBUTES结构指针,可为NULL  BOOL bManualReset, // 手动/自动  // TRUE:表示手动,在WaitFo...
  • eventpp -- 用于事件调度程序和回调列表的 C++ 库 eventpp 是一个用于回调、事件调度器和事件队列的 C++ 事件库。 使用 eventpp,您可以轻松实现信号和插槽机制、发布者和订阅者模式或观察者模式。 事实和特点 强大...
  • C++事件委托

    2013-10-30 09:26:30
    摘要: 介绍了事件委托机制的需求,各种解决方案的演变,最终提出模板化的事件委托机制,并给出较详细的进化过程和原理说明。
  • c++实现委托和事件

    2014-11-23 02:58:39
    使用c++的function和bind实现c#中的委托和事件
  • 这是一个Visual C++临界区域线程同步的简单实例工程。
  • 一个用c++编写的模拟银行系统,基于数据结构的事件驱动。
  • 事件模型是被广泛使用的好东西,但是C++标准库里没有现成的,其他实现又复杂或者不优雅,比如需要使用宏。现在VC11可以用在XP下了,那么痛快的拿起C++11提供的先进设施组合出一个轻便的实现吧。  为了达到简洁的...
  • C++事件的建立和使用SetEvent,ResetEvent

    千次阅读 2016-11-28 21:02:03
    一、事件是很常用的多线程同步互斥机制  函数原型如下所示,一共四个参数: HANDLE CreateEvent(  LPSECURITY_ATTRIBUTES lpEventAttributes, // SECURITY_ATTRIBUTES结构指针,可为NULL  BOOL bManualReset...
  • C++ 事件回调机制的几种实现方式

    千次阅读 2015-01-12 22:35:41
    1、duilib中的CEventSource。以下代码摘自duilib,并且有一点改动。 delegate.h #include class CDelegateBase { ... CDelegateBase(void* pObject, void* pFn);... CDelegateBase(const CDelegateBase& rhs);...
  • C++事件(Event)机制的实现

    千次阅读 2011-10-19 23:26:43
    C++事件(Event)机制的实现 2007-10-01 14:13 752人阅读 评论(0) 收藏 举报 用C++实现事件机制我以前写过一个小例子,但不是很完善,比如Event只能接受全局函数作为handler,类成员方法不可以,还有一个...
  • 主要介绍了C++设置事件通知线程工作的方法,是Windows应用程序设计中非常实用的技巧,需要的朋友可以参考下
  • 今天小编就为大家分享一篇C/C++获取键盘事件的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • c++事件及管道通信

    千次阅读 2012-10-18 10:00:44
    事件通信: 事件通信主要是发送信号,作为事件通知使用,占用资源少,速度快  发送端: hEvent = ::CreateEvent(NULL,TRUE,FALSE,_T("MYMESSAGE")); if ((hEvent == INVALID_HANDLE_VALUE) || (hEvent == 0)) {...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 203,060
精华内容 81,224
关键字:

c++事件

c++ 订阅