c++ 11以前要实现 signal slot 非常麻烦,需要重写很多代码。之前使用 libsig++ 后来发现 这代码中与qt 的slots emit等名称冲突。虽然可以解决,但是比较麻烦。所以 就使用 新的 c++特性,自行实现了简单的 signal 类。 目前实现比较简单。没有太多考虑异常或者智能情况。
这里面包含了结合线程使用,编程异步信号的 部分代码.需要屏蔽掉才能正常使用.
#include <functional>
#include <map>
#include <vector>
#include "ScTypes.h"
#include "ScCoreDefine.h"
#define AsyncSignal
#ifdef AsyncSignal
#include "ScAsyncMessage.h"
#include "ScThread.h"
#include "ScMutex.h"
#include "ScReadWriteLock.h"
#endif
#ifdef PostMessage
#define PostMessageOld PostMessage
#undef PostMessage
#endif
// A signal object may call multiple slots with the
// same signature. You can connect functions to the signal
// which will be called when the emit() method on the
// signal object is invoked. Any argument passed to emit()
// will be passed to the given functions.
//异步消息大约每秒d 70 万 r 500w
//不可使用引用作参数
namespace SimpleCpp {
class CThread;
class SCCORE_API CSignalInitializer {
public:
CSignalInitializer();
~CSignalInitializer();
static CThread* m_pThreadDefault;
static CSignalInitializer m_signalInitializer;
};
template <class T_Ret, typename... Args>
class CSignalConnection {
public:
CSignalConnection() {
}
CSignalConnection(const CSignalConnection& other) {
m_pFun = other.m_pFun;
m_pObject = other.m_pObject;
m_function = other.m_function;
}
~CSignalConnection()
{
}
CSignalConnection& operator =(const CSignalConnection& other) {
m_pFun = other.m_pFun;
m_pObject = other.m_pObject;
m_function = other.m_function;
return *this;
}
public:
std::function<T_Ret(Args...)> m_function;
void* m_pFun;
void* m_pObject;
};
template <class T_Ret, typename... Args>
class CSignal {
public:
CSignal(void* pOwner=nullptr, bool bThreadSafe=true)
#ifdef AsyncSignal
: m_pThread(nullptr)
#endif
//, m_pMutex(nullptr)
, m_pOwner(pOwner)
{
//默认都要打开线程安全
if (bThreadSafe)
{
//m_pMutex = new CMutex();
m_pRWLock = new CReadWriteLock();
}
}
// copy creates new signal
CSignal(CSignal const& other)
#ifdef AsyncSignal
: m_pThread(nullptr)
#endif
//, m_pMutex(nullptr)
{
// if (other.m_pMutex)
// {
// m_pMutex = new CMutex();
// }
}
~CSignal() {
// for (auto it : m_lstSlots) {
// delete it.first;
// }
if (m_pThread)
{
//m_pThread->RemoveMessage(this);
m_pThread->RemoveSignal(this);
}
for (int i=0; i<m_lstSlots.size(); i++)
{
delete m_lstSlots[i];
}
m_lstSlots.clear();
// if (m_pMutex)
// {
// delete m_pMutex;
// m_pMutex = nullptr;
// }
if (m_pRWLock)
{
delete m_pRWLock;
m_pRWLock = nullptr;
}
}
// connects a member function of a given object to this Signal
// template < typename T_Fun, typename T_O, typename... A>
// int Connect(T_Fun&& fun, T_O&& object, A&& ... a)
template < typename T_Fun, typename... A>
int Connect(T_Fun&& fun, A&& ... a)
{
ScDebug("%s: ptr fun \n", __FUNCTION__);
CSignalConnection<T_Ret, Args...> *pConnection = new CSignalConnection<T_Ret, Args...>();
pConnection->m_pFun = (void*)*(long long*)&fun;
pConnection->m_pObject = (void*)nullptr;
pConnection->m_function = std::bind(fun, a...);
//pConnection->m_function = std::bind(fun, object, a...);
//m_lstSlots.insert({ ++m_Id, std::bind(fun, object, a...) });
//m_lstSlots.insert({ pFunction, pFunction->m_function });
// if (m_pMutex)
// {
// m_pMutex->Lock();
// m_lstSlots.push_back(pConnection);
// m_pMutex->Unlock();
// }
if (m_pRWLock)
{
m_pRWLock->LockForWrite();
m_lstSlots.push_back(pConnection);
m_pRWLock->UnlockForWrite();
}
else
{
m_lstSlots.push_back(pConnection);
}
return 0;
}
// template < typename T_Fun>
// int Connect(T_Fun&& fun)
// {
// ScDebug("%s: ptr fun \n", __FUNCTION__);
// CSignalConnection<T_Ret, Args...> *pConnection = new CSignalConnection<T_Ret, Args...>();
// pConnection->m_pFun = (void*)*(long long*)&fun;
// pConnection->m_pObject = (void*)nullptr;
//
// pConnection->m_function = std::bind(fun);
// //pConnection->m_function = std::bind(fun, object, a...);
// if (m_pRWLock)
// {
// m_pRWLock->LockForWrite();
// m_lstSlots.push_back(pConnection);
// m_pRWLock->UnlockForWrite();
// }
// else
// {
// m_lstSlots.push_back(pConnection);
// }
//
// return 0;
// }
template <typename T_Ret1, typename T_O, typename... A>
int Connect(T_Ret1 T_O::* fun, T_O* object, A&& ... a) {
ScDebug("%s: mem fun \n", __FUNCTION__);
CSignalConnection<T_Ret, Args...> *pConnection = new CSignalConnection<T_Ret, Args...>();
pConnection->m_pFun = (void*)*(long long*)&fun;//(void*)*(long long*)&fun;
pConnection->m_pObject = (void*)object;
pConnection->m_function = std::bind(fun, object, a...);
if (m_pRWLock)
{
m_pRWLock->LockForWrite();
m_lstSlots.push_back(pConnection);
m_pRWLock->UnlockForWrite();
}
else
{
m_lstSlots.push_back(pConnection);
}
return 0;
}
template < typename T_Fun, typename... A>
int Connect1(T_Fun* fun, A&& ... a) {
ScDebug("%s: ptr fun \n", __FUNCTION__);
CSignalConnection<T_Ret, Args...> *pConnection = new CSignalConnection<T_Ret, Args...>();
pConnection->m_pFun = (void*)*(long long*)fun;
pConnection->m_pObject = (void*)nullptr;
pConnection->m_function = std::bind(fun, a...);
if (m_pRWLock)
{
m_pRWLock->LockForWrite();
m_lstSlots.push_back(pConnection);
m_pRWLock->UnlockForWrite();
}
else
{
m_lstSlots.push_back(pConnection);
}
return 0;
}
template <typename T_Ret1, typename T_O, typename... A>
int Connect1(T_Ret1 T_O::* fun, T_O* object, A&& ... a) {
ScDebug("%s: mem fun \n", __FUNCTION__);
CSignalConnection<T_Ret, Args...> *pConnection = new CSignalConnection<T_Ret, Args...>();
pConnection->m_pFun = (void*)*(long long*)&fun;//(void*)*(long long*)&fun;
pConnection->m_pObject = (void*)object;
pConnection->m_function = std::bind(fun, object, a...);
if (m_pRWLock)
{
m_pRWLock->LockForWrite();
m_lstSlots.push_back(pConnection);
m_pRWLock->UnlockForWrite();
}
else
{
m_lstSlots.push_back(pConnection);
}
return 0;
}
template <typename T_Fun, typename T_O, typename... A>
CSignalConnection<T_Ret, Args...> MemFun(T_Fun&& fun, T_O&& object, A&& ... a)
{
CSignalConnection<T_Ret, Args...> connection;
connection.m_pFun = (void*)*(long long*)&fun;
connection.m_pObject = (void*)&object;
connection.m_function = std::bind(fun, object, a...);
return connection;
}
template <typename T_Fun, typename T_O, typename... A>
CSignalConnection<T_Ret, Args...> Fun(T_Fun&& fun, T_O&& object, A&& ... a)
{
CSignalConnection<T_Ret, Args...> connection;
connection.m_pFun = (void*)*(long long*)&fun;
connection.m_pObject = (void*)&object;
connection.m_function = std::bind(fun, object, a...);
return connection;
}
template <typename T_Fun, typename... A>
CSignalConnection<T_Ret, Args...> PtrFun(T_Fun&& fun, A&& ... a)
{
CSignalConnection<T_Ret, Args...> connection;
connection.m_pFun = (void*)*(long long*)&fun;
connection.m_pObject = nullptr;
//function.function = std::bind(fun, a...);
return connection;
}
// connects a free function to the signal. The returned
// can not use std::bind, use function ptr directly
int Connect(std::function<T_Ret(Args...)> const& fun) {
typedef T_Ret T_Fun(Args...);
T_Fun* pFun = nullptr;
long long* pTmp = (long long*)fun.template target<T_Ret(*)(Args...)>();
// fun.template target<decltype(pFun)>();
//int64* pTmp = (int64*)fun.target<decltype(pFun)>();
if (pTmp == nullptr)
{//不能使用bind 方式绑定.
return -1;
}
// ;
CSignalConnection<T_Ret, Args...> *pConnection = new CSignalConnection<T_Ret, Args...>();
//pFunction->pFun = (void*)*(int64*)function.target<T_Ret(Args...)>();
pConnection->m_pFun = (void*)*pTmp;
pConnection->m_pObject = nullptr;
pConnection->m_function = fun;
//m_lstSlots.insert({ pFunction, fun });
// if (m_pMutex)
// {
// m_pMutex->Lock();
// m_lstSlots.push_back(pConnection);
// m_pMutex->Unlock();
// }
if (m_pRWLock)
{
m_pRWLock->LockForWrite();
m_lstSlots.push_back(pConnection);
m_pRWLock->UnlockForWrite();
}
else
{
m_lstSlots.push_back(pConnection);
}
return 0;
}
//成员函数 mem function, 不可使用bind
template < typename T_Fun, typename T_O, typename... A>
int Disconnect(T_Fun&& fun, T_O&& object, A&& ... a) {
CSignalConnection<T_Ret, Args...> connection;
connection.m_pFun = (void*)*(long long*)&fun;
connection.m_pObject = (void*)object;
// if (m_pMutex)
// {
// m_pMutex->Lock();
// }
if (m_pRWLock)
{
m_pRWLock->LockForWrite();
}
typename std::vector<CSignalConnection<T_Ret, Args...> *> ::iterator item;
for (item = m_lstSlots.begin(); item != m_lstSlots.end(); item++) {
CSignalConnection<T_Ret, Args...>* pConnectionTmp;
pConnectionTmp = *item;
if (pConnectionTmp->m_pFun == connection.m_pFun
&& pConnectionTmp->m_pObject == connection.m_pObject)
{
item = m_lstSlots.erase(item);
delete pConnectionTmp;
break;
}
}
// if (m_pMutex)
// {
// m_pMutex->Unlock();
// }
if (m_pRWLock)
{
m_pRWLock->UnlockForWrite();
}
return 0;
}
//断开普通函数 free function , 不可使用 bind
int Disconnect(std::function<T_Ret(Args...)> const& fun) {
long long* pTmp = (long long*)fun.template target<T_Ret(*)(Args...)>();
if (pTmp == nullptr)
{//不能使用bind 方式绑定.
return -1;
}
CSignalConnection<T_Ret, Args...> connection;
connection.m_pFun = (void*)*pTmp;
connection.m_pObject = nullptr;
// if (m_pMutex)
// {
// m_pMutex->Lock();
// }
if (m_pRWLock)
{
m_pRWLock->LockForWrite();
}
typename std::vector<CSignalConnection<T_Ret, Args...> *> ::iterator item;
for (item = m_lstSlots.begin(); item != m_lstSlots.end(); item++) {
CSignalConnection<T_Ret, Args...>* pConnectionTmp;
pConnectionTmp = *item;
if (pConnectionTmp->m_pFun == connection.m_pFun
&& pConnectionTmp->m_pObject == connection.m_pObject)
{
item = m_lstSlots.erase(item);
delete pConnectionTmp;
break;
}
}
// if (m_pMutex)
// {
// m_pMutex->Unlock();
// }
if (m_pRWLock)
{
m_pRWLock->UnlockForWrite();
}
return 0;
}
int Connect(CSignalConnection<T_Ret, Args...> connection)
{
CSignalConnection<T_Ret, Args...>* pNewConnection = new CSignalConnection<T_Ret, Args...>(connection);
//m_lstSlots.insert({ pFunction, function.m_function });
// if (m_pMutex)
// {
// m_pMutex->Lock();
// }
if (m_pRWLock)
{
m_pRWLock->LockForWrite();
}
m_lstSlots.push_back(pNewConnection);
// if (m_pMutex)
// {
// m_pMutex->Unlock();
// }
if (m_pRWLock)
{
m_pRWLock->UnlockForWrite();
}
return 0;
}
// disconnects a previously connected function
// disconnects all previously connected functions
void Clear() {
// for (auto it : m_lstSlots) {
// delete *it;
// }
// if (m_pMutex)
// {
// m_pMutex->Lock();
// }
if (m_pRWLock)
{
m_pRWLock->LockForWrite();
}
for (int i = 0; i < m_lstSlots.size(); i++)
{
delete m_lstSlots[i];
}
m_lstSlots.clear();
// if (m_pMutex)
// {
// m_pMutex->Unlock();
// }
if (m_pRWLock)
{
m_pRWLock->UnlockForWrite();
}
}
// calls all connected functions
T_Ret Emit(Args... p) {
bool bVoid = std::is_same<T_Ret, void>::value;
T_Ret ret(0);
#ifdef AsyncSignal
if (m_pThread)
{//异步信号
//为了锁住 m_pThread 不被detach
m_pRWLock->LockForWrite();
if (!m_pThread)
{
m_pRWLock->UnlockForWrite();
return ret;
}
CAsyncMessage<T_Ret, Args...>* pMessage = new CAsyncMessage<T_Ret, Args...>(p...);
//pMessage->SetParams(p...);
pMessage->m_pSignal = this;
pMessage->m_pUserData = this;
m_pThreadMessage = pMessage;
m_pThread->PostMessage(pMessage);
m_pRWLock->UnlockForWrite();
}
else
#endif
{
// if (m_pMutex)
// {
// m_pMutex->Lock();
// }
if (m_pRWLock)
{
m_pRWLock->LockForRead();
}
for (int i = 0; i < m_lstSlots.size(); i++)
{
m_lstSlots[i]->m_function(p...);
}
// if (m_pMutex)
// {
// m_pMutex->Unlock();
// }
if (m_pRWLock)
{
m_pRWLock->UnlockForRead();
}
}
return ret;
}
//发射异步信号
T_Ret EmitAsync(CThread* pThread, Args... p) {
T_Ret ret(0);
#ifdef AsyncSignal
if (pThread)
{//异步信号
CAsyncMessage<T_Ret, Args...>* pMessage = new CAsyncMessage<T_Ret, Args...>(p...);
//pMessage->SetParams(p...);
pMessage->m_pSignal = this;
m_pThreadMessage = pMessage;
pThread->PostMessage(pMessage);
}
else
#endif
{
// if (m_pMutex)
// {
// m_pMutex->Lock();
// }
if (m_pRWLock)
{
m_pRWLock->LockForRead();
}
for (int i = 0; i < m_lstSlots.size(); i++)
{
m_lstSlots[i]->m_function(p...);
}
// if (m_pMutex)
// {
// m_pMutex->Unlock();
// }
if (m_pRWLock)
{
m_pRWLock->UnlockForRead();
}
}
return ret;
}
// assignment creates new Signal
CSignal& operator=(CSignal const& other) {
Clear();
return *this;
}
vector<CSignalConnection<T_Ret, Args...>*>& GetSlots()
{
return m_lstSlots;
}
//附加到 thread, 那么消息将发到该线程去处理
//也将是异步信号
int AttachThread(CThread* pThread) {
if (pThread == nullptr)
{
m_pThread = CSignalInitializer::m_pThreadDefault;
}
else {
m_pThread = pThread;
}
// if (!m_pMutex)
// {//异步的一定需要是线程安全的。
// m_pMutex = new CMutex();
// }
if (!m_pRWLock)
{//异步的一定需要是线程安全的。
m_pRWLock = new CReadWriteLock();
}
return 0;
};
int DetachThread(/*CThread* pThread*/)
{
m_pThread = nullptr;
return 0;
}
int GetCount() {
int nCount(0);
// if (m_pMutex)
// {
// m_pMutex->Lock();
// nCount = m_lstSlots.size();
// m_pMutex->Unlock();
// }
if (m_pRWLock)
{
m_pRWLock->LockForRead();
nCount = m_lstSlots.size();
m_pRWLock->UnlockForRead();
}
else {
nCount = m_lstSlots.size();
}
return nCount;
}
//
CThread* GetThread() {
return m_pThread;
};
bool Lock() {
// if (!m_pMutex)
// {
// return false;
// }
// return m_pMutex->Lock();
if (!m_pRWLock)
{
return false;
}
return m_pRWLock->LockForRead();
};
bool Unlock()
{
// if (!m_pMutex)
// {
// return false;
// }
// return m_pMutex->Unlock();
if (!m_pRWLock)
{
return false;
}
m_pRWLock->UnlockForRead();
return true;
};
void* GetOwner()
{
return m_pOwner;
}
void SetOwner(void* pOwner)
{
m_pOwner = pOwner;
}
protected:
//std::map<int, std::function<T_Ret(Args...)>> m_lstSlots;;
//std::map<CFunction<T_Ret, Args...>*, std::function<T_Ret(Args...)>> m_lstSlots;
std::vector<CSignalConnection<T_Ret, Args...>*> m_lstSlots;
CThread* m_pThread;
//CMutex* m_pMutex;
CReadWriteLock* m_pRWLock=nullptr;
void* m_pOwner;
CThreadMessage* m_pThreadMessage=nullptr;
};
使用connect或者disconnect, 直接传入函数地址。不要使用bind 方式传入。 这是为了 保存函数 地址和对象地址。以便 disconnect
测试(进行了修改,自由函数或者成员函数不再需要bind函数区分):
int TestFun()
{
return 0;
}
class CTestClass {
public:
int TestFun()
{
return 0;
}
};
void TestSignal1()
{
CTestClass obj;
CSignal<int> sig;
//sig.MemFun(&CTestClass::TestFun, &obj);
sig.Connect(&CTestClass::TestFun, &obj);
sig.Connect(&TestFun);
ScDebug("%s: %p, %p\n", __FUNCTION__, &CTestClass::TestFun, &TestFun);
//Function(&CTestClass::TestFun);
//Function(&TestFun);
}
此类内部,有 thread。可以自行屏蔽。这是为了扩展为线程异步信号。
类似qt 信号一样。可以让信号在某个线程中异步回调Slot。
传统的 异步消息处理方式 都是 case xxxx: OnXXX这样为程序扩展带来很大麻烦。每一个消息需要做函数映射处理,同时消息处理函数必须是完全是相同参数。
直接将信号扩展为异步信号。可以在任何时候,灵活绑定行程异步消息处理过程。同时可以使用任意参数的函数做消息和对应处理函数。 这可以极大方便程序使用。 后面再继续贴出线程异步信号