非模板类中的模板方法中的Dll和静态变量

6

我花了几天的时间寻找解决问题的方法,但没有找到任何可行的解决方案。

我有一个名为ServiceEventHub的类,负责在应用程序中分发事件。这段代码是受到我在网上找到的实现事件聚合器的启发而编写的。该应用程序是一个插件引擎,动态加载不同的dll(插件)。该类是引擎提供的服务,驻留在应用程序(.exe)中。

问题在于该类依赖于静态变量来跟踪不同的“事件”发射和注册(事件仅仅是在公共头文件中定义的结构体)。从我的理解来看,由于Windows默认情况下不导出符号,因此静态变量不是应用程序和dll中的相同实例。正如你所想象的那样,“事件类型”在引擎和插件之间不是相同的,因此它的表现与预期不同。这是我第一次在Windows上开发,我有点迷失了方向。

由于某些方法使用模板,我无法将其实现移到cpp文件中。我已经尝试使用dllexport/dllimport方法,但由于该类使用模板,再次失败了。此外,在我的情况下,是应用程序导出了dll导入,不确定是否应该这样做。

我还看了一下#pragma data_seg,但不知道如何使用它。是针对整个类吗?只是使用静态变量的两个方法吗?

以下是完整的代码:

class ServiceEventHub
{
public:

template <class EventType>
using Slot = std::function<void(const EventType&)>;

ServiceEventHub()
{

}

template <typename EventType>
void subscribe(Slot<EventType> callable)
{
    LOG_FUNC_ENTER();

    std::lock_guard<std::recursive_mutex> lock(m_mutex);
    size_t type = Event<EventType>::type();

    if (type >= m_subscribers.size())
    {
        m_subscribers.resize(type + 1);
    }

    m_subscribers[type].push_back(CallbackWrapper<EventType>(callable));
}

template <typename EventType>
void emit(EventType&& event)
{
    LOG_FUNC_ENTER(typeid(EventType).name());

    // Critical section starts
    std::lock_guard<std::recursive_mutex> lock(m_mutex);
    size_t type = Event<EventType>::type();

    if (type >= m_subscribers.size())
    {
        return;
    }

    Event<EventType> eventWrapper(std::forward<EventType>(event));
    for (auto& receiver : m_subscribers[type])
    {
        m_ioService.post(boost::bind(receiver, eventWrapper));
    }

    // Critical section ends
}

private:

struct BaseEvent
{
    virtual ~BaseEvent() {}
protected:
    static size_t getNextType()
    {
        static size_t s_typeCount{ 0 };
        return s_typeCount++;
    }
};

template <typename EventType>
struct Event : BaseEvent
{
    static size_t type()
    {
        static size_t s_type = BaseEvent::getNextType();
        return s_type;
    }
    Event(EventType&& event)
        : event_(std::forward<EventType>(event))
    {
    }
    EventType event_;
};

template <typename EventType>
struct CallbackWrapper
{
    CallbackWrapper(Slot<EventType> callable)
        : m_callable(callable)
    {
    }

    void operator()(const BaseEvent& event)
    {
        m_callable(static_cast<const Event<EventType>&>(event).event_);
    }

    Slot<EventType> m_callable;
};

void workerThread(boost::asio::io_service* ioService)
{
    LOG_FUNC_ENTER();

    ioService->run();
}

std::vector<std::vector<Slot<BaseEvent> > > m_subscribers = {};
std::recursive_mutex                        m_mutex;
boost::asio::io_service                     m_ioService{};
boost::asio::io_service::work               m_ioWork{m_ioService};
std::thread                                 m_thread{boost::bind(&ServiceEventHub::workerThread, this, &m_ioService)};
};

非常感谢您的帮助。


如果这里没有人知道...我正在失去希望 :/ 我可能不得不避免使用模板,而选择老式的枚举,并让我的结构体事件从一个基类继承。 - kashikai
1个回答

1

我通过使用模板类型信息成功避免了使用静态计数器:

static size_t type()
{
    return typeid(EventType).hash_code();
}

根据我在网上的阅读,实现应确保返回值对于一个类型是唯一的,并且 type1.hash_code == type2.hash_code 意味着 type1 == type2。

以下是代码:

class ServiceEventHub
{
public:

template <class EventType>
using Slot = std::function<void(const EventType&)>;

template <typename EventType>
void subscribe(Slot<EventType> callable)
{
    LOG_FUNC_ENTER();

    size_t type = Event<EventType>::type();

    // Critical section starts
    std::lock_guard<std::recursive_mutex> lock(m_mutex);
    auto search = m_subscribers.find(type);

    if (search != m_subscribers.cend())
    {
        search->second.push_back(CallbackWrapper<EventType>(callable));
    }
    else
    {
        m_subscribers[type] = { CallbackWrapper<EventType>(callable) };
    }
    // Critical section ends
}

template <typename EventType>
void emit(EventType&& event)
{
    LOG_FUNC_ENTER(typeid(EventType).name());

    size_t type = Event<EventType>::type();

    // Critical section starts
    std::lock_guard<std::recursive_mutex> lock(m_mutex);
    auto typeCallbacks = m_subscribers.find(type);

    if (typeCallbacks == m_subscribers.cend())
    {
        return;
    }

    Event<EventType> eventWrapper(std::forward<EventType>(event));

    for (auto& receiver : typeCallbacks->second)
    {
        m_ioService.post(boost::bind(receiver, eventWrapper));
    }
    // Critical section ends
}

private:

struct BaseEvent
{
    virtual ~BaseEvent() {}
};

template <typename EventType>
struct Event : BaseEvent
{
    static size_t type()
    {
        return typeid(EventType).hash_code();
    }
    Event(EventType&& event)
        : event_(std::forward<EventType>(event))
    {
    }
    EventType event_;
};

template <typename EventType>
struct CallbackWrapper
{
    CallbackWrapper(Slot<EventType> callable)
        : m_callable(callable)
    {
    }

    void operator()(const BaseEvent& event)
    {
        m_callable(static_cast<const Event<EventType>&>(event).event_);
    }

    Slot<EventType> m_callable;
};

void workerThread(boost::asio::io_service* ioService)
{
    LOG_FUNC_ENTER();

    ioService->run();
}

std::map<size_t, std::vector<Slot<BaseEvent> > >    m_subscribers = {};
std::recursive_mutex                                m_mutex;
boost::asio::io_service                             m_ioService{};
boost::asio::io_service::work                       m_ioWork{m_ioService};
std::thread                                          
m_thread{boost::bind(&ServiceEventHub::workerThread, this, &m_ioService)};
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接