boost::signal

程序开发基础学习四(boost::signal2 函数学习) 在游戏编程中,新的策划需求总是在迭代不停。。。。。。,对于游戏程序员肯定深有感触吧,遇到这种情况咱只能小小的抱怨下,活还得干。尤其是遇到耦合到很多类的时候,要是直接实现不加抽象的话,那咱的代码就要被拆的七零八落,并且在代码维护性和程序健壮性上问题很大。前面说到的问题其实就是常听到 阅读详情

比特币源码分析-boost::signal 的使用


2378

bitcoin 代码中大量使用 boost::signal, boost::signal 实现了信号与槽的事件通知机制,或者说是一种消息的发布与订阅机制, signal 类型是一个可调用类型,slot 就是callback 对象,或者说事件的订阅者,signal 实例是一个可调用对象,调用signal 对象,就相当于发布了相应的事件, signal 的connect, disconnect 方法分别相当于对事件的订阅,取消。

#include <boost/signals2.hpp>
 #include 
 void print_args(float x, float y)
 {
 std::cout << "The arguments are " << x << " and " << y << std::endl;
 }
 void print_sum(float x, float y)
 {
 std::cout << "The sum is " << x + y << std::endl;
 }
 void print_product(float x, float y)
 {
 std::cout << "The product is " << x * y << std::endl;
 }
 void print_difference(float x, float y)
 {
 std::cout << "The difference is " << x - y << std::endl;
 }
 void print_quotient(float x, float y)
 {
 std::cout << "The quotient is " << x / y << std::endl;
 }
 int main() {
 boost::signals2::signal<void(float, float)> sig;
 sig.connect(print_args);
 sig.connect(print_sum);
 sig.connect(print_product);
 sig.connect(print_difference);
 sig.connect(print_quotient);
 sig(5., 3.);
 return 0;

上面这个例子, 有五个函数订阅sig 事件,sig(5. , 3.) 的调用触发事件,参数5,3,相当于事件携带的消息paylaod, 传给了五个事件订阅者。

bitcoin 中定义了类型CMainSignals 来统一管理各个功能模块的事件通知,CMainSignal 是一个资源管理类型, 主要工作代理给由unique_ptr 管理内存的成员 m_internals , 它的类型是MainSignalsInstance,内部定义十个boost signal 变量, 分别表达十种要通知的事件。

class CMainSignals {
 private:
 std::unique_ptr m_internals;
 friend void ::RegisterValidationInterface(CValidationInterface*);
 friend void ::UnregisterValidationInterface(CValidationInterface*);
 friend void ::UnregisterAllValidationInterfaces();
 friend void ::CallFunctionInValidationInterfaceQueue(std::function func); void MempoolEntryRemoved(CTransactionRef tx, MemPoolRemovalReason reason);public: /** Register a CScheduler to give callbacks which should run in the background (may only be called once) */
 void RegisterBackgroundSignalScheduler(CScheduler& scheduler);
 /** Unregister a CScheduler to give callbacks which should run in the background - these callbacks will now be dropped! */
 void UnregisterBackgroundSignalScheduler();
 /** Call any remaining callbacks on the calling thread */
 void FlushBackgroundCallbacks();
 size_t CallbacksPending();
 /** Register with mempool to call TransactionRemovedFromMempool callbacks */
 void RegisterWithMempoolSignals(CTxMemPool& pool);
 /** Unregister with mempool */
 void UnregisterWithMempoolSignals(CTxMemPool& pool);
 void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload);
 void TransactionAddedToMempool(const CTransactionRef &);
 void BlockConnected(const std::shared_ptr &, const CBlockIndex *pindex, const std::shared_ptr> &);
 void BlockDisconnected(const std::shared_ptr &);
 void SetBestChain(const CBlockLocator &);
 void Inventory(const uint256 &);
 void Broadcast(int64_t nBestBlockTime, CConnman* connman);
 void BlockChecked(const CBlock&, const CValidationState&);
 void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr&);
 };
 struct MainSignalsInstance {
 boost::signals2::signal UpdatedBlockTip;
 boost::signals2::signal TransactionAddedToMempool;
 boost::signals2::signal &, const CBlockIndex *pindex, const std::vector&)> BlockConnected;
 boost::signals2::signal &)> BlockDisconnected;
 boost::signals2::signal TransactionRemovedFromMempool;
 boost::signals2::signal SetBestChain;
 boost::signals2::signal Inventory;
 boost::signals2::signal Broadcast;
 boost::signals2::signal BlockChecked;
 boost::signals2::signal&)> NewPoWValidBlock;
 // We are not allowed to assume the scheduler only runs in one thread,
 // but must ensure all callbacks happen in-order, so we end up creating
 // our own queue here :(
 SingleThreadedSchedulerClient m_schedulerClient;
 explicit MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
 };

类型CValidationInterface 主要是统一表示某些对MainSignalsInstance 中定义的十个事件感兴趣的对象, 即这些事件的订阅者, 所有对这些事件感兴趣代码继承CValidationInterface类型,提供自己版本的这些虚成员函数的实现,覆盖baseCValidationInterface 中对应的空方法, 表达对相应的事件感兴趣, 不感兴趣的事件的回调方法继续是那些继承自base class 的空方法。

class CValidationInterface {
 protected:
 virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {}
 virtual void TransactionAddedToMempool(const CTransactionRef &ptxn) {}
 virtual void TransactionRemovedFromMempool(const CTransactionRef &ptx) {}
 virtual void BlockConnected(const std::shared_ptr &block, const CBlockIndex *pindex, const std::vector &txnConflicted) {}
 virtual void BlockDisconnected(const std::shared_ptr &block) {}
 virtual void SetBestChain(const CBlockLocator &locator) {}
 virtual void Inventory(const uint256 &hash) {}
 virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
 virtual void BlockChecked(const CBlock&, const CValidationState&) {}
 virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr& block) {};
 friend void ::RegisterValidationInterface(CValidationInterface*);
 friend void ::UnregisterValidationInterface(CValidationInterface*);
 friend void ::UnregisterAllValidationInterfaces();
 };

CValidationInterface 有四个子类, CWallet , CZMQNotificationInterface, submitblock_StateCatcher, PeerLogicValidation 分别对应四个对MainSignalsInstance 中的事件感兴趣的订阅者。

 class CWallet final : public CCryptoKeyStore, public CValidationInterface
 {
 ...............
 void TransactionAddedToMempool(const CTransactionRef& tx) override;
 void BlockConnected(const std::shared_ptr& pblock, const CBlockIndex *pindex, const std::vector& vtxConflicted) override;
 void BlockDisconnected(const std::shared_ptr& pblock) override;
 void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
 void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;
 void SetBestChain(const CBlockLocator& loc) override;
 void Inventory(const uint256 &hash) override
 {
 {
 LOCK(cs_wallet);
 std::map<uint256, int>::iterator mi = mapRequestCount.find(hash);
 if (mi != mapRequestCount.end())
 (*mi).second++;
 }
 }
 ...............
 };
 class CZMQNotificationInterface final : public CValidationInterface
 {
 ................
 // CValidationInterface
 void TransactionAddedToMempool(const CTransactionRef& tx) override;
 void BlockConnected(const std::shared_ptr& pblock, const CBlockIndex* pindexConnected, const std::vector& vtxConflicted) override;
 void BlockDisconnected(const std::shared_ptr& pblock) override;
 void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
 .................
 };
 class submitblock_StateCatcher : public CValidationInterface
 {
 public:
 uint256 hash;
 bool found;
 CValidationState state;
 explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
 protected:
 void BlockChecked(const CBlock& block, const CValidationState& stateIn) override {
 if (block.GetHash() != hash)
 return;
 found = true;
 state = stateIn;
 }
 };
 class PeerLogicValidation : public CValidationInterface, public NetEventsInterface
 {
 private:
 CConnman* const connman;
 public:
 explicit PeerLogicValidation(CConnman* connman, CScheduler &scheduler);
 void BlockConnected(const std::shared_ptr& pblock, const CBlockIndex* pindexConnected, const std::vector& vtxConflicted) override;
 void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
 void BlockChecked(const CBlock& block, const CValidationState& state) override;
 void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr& pblock) override;
 ........
 };

这四个订阅者通过调用RegisterValidationInterface, UnregisterValidationInterface 订阅,取消事件通知,函数接受参数是指向订阅者的指针。

void RegisterValidationInterface(CValidationInterface* pwalletIn) {
 g_signals.m_internals->UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
 g_signals.m_internals->TransactionAddedToMempool.connect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
 g_signals.m_internals->BlockConnected.connect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
 g_signals.m_internals->BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
 g_signals.m_internals->TransactionRemovedFromMempool.connect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1));
 g_signals.m_internals->SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
 g_signals.m_internals->Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
 g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
 g_signals.m_internals->BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
 g_signals.m_internals->NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
 }
 void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
 g_signals.m_internals->BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
 g_signals.m_internals->Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
 g_signals.m_internals->Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
 g_signals.m_internals->SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
 g_signals.m_internals->TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
 g_signals.m_internals->BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
 g_signals.m_internals->BlockDisconnected.disconnect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
 g_signals.m_internals->TransactionRemovedFromMempool.disconnect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1));
 g_signals.m_internals->UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
 g_signals.m_internals->NewPoWValidBlock.disconnect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
 }

在程序启动,初始化阶段,启动调度器线程

bool AppInitMain()
 {
 .................
 CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler);
 threadGroup.create_thread(boost::bind(&TraceThread, "scheduler", serviceLoop));
 .................
 }

调用RegisterBackgroundSignalScheduler(), 初始化全局MainSignalsInstance 实例; 调用RegisterWithMempoolSignals(), 订阅全局内存池对象的NotifyEntryRemoved 事件通知, MainSignalsInstance 只对由于超时,大小限制, blockchian 重组,替换等原因发生的离开内存池事件感兴趣, 收到后MainSignalsInstance 再作为事件发布者, 转发给其他订阅者, 如CWallet。

bool AppInitMain()
 {
 ......
 GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
 GetMainSignals().RegisterWithMempoolSignals(mempool);
 ........
 }

初始化全局的连接管理对象connman 后, 初始化全局的peerLogic 对象, 然后调用RegisterValidationInterface(), peerLogic 成为MainSignalsInstance 对象的订阅者, 如果用户编译了zeromq支持模块,调用RegisterValidationInterface(), pzmqNotificationInterface 订阅MainSignalsInstance 。

bool AppInitMain()
 {
 .............
 assert(!g_connman);
 g_connman = std::unique_ptr(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max())));
 CConnman& connman = *g_connman;
peerLogic.reset(new PeerLogicValidation(&connman, scheduler));
 RegisterValidationInterface(peerLogic.get());
 .............
 #if ENABLE_ZMQ
 pzmqNotificationInterface = CZMQNotificationInterface::Create();
 if (pzmqNotificationInterface) {
 RegisterValidationInterface(pzmqNotificationInterface);
 }
 #endif
 ...............
 }

如果钱包功能开启, 启动后打开钱包过程,会把钱包注册成为MainSignalsInstance的订阅者。

bool AppInitMain()
 {
 ........
 #ifdef ENABLE_WALLET
 if (!OpenWallets())
 return false;
 #else
 LogPrintf("No wallet support compiled in!\n");
 #endif
 ........
 }
 bool OpenWallets()
 {
 if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
 LogPrintf("Wallet disabled!\n");
 return true;
 }
 for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
 CWallet * const pwallet = CWallet::CreateWalletFromFile(walletFile);
 if (!pwallet) {
 return false;
 }
 vpwallets.push_back(pwallet);
 }
 return true;
 }
CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
 {
 ......
 CWallet *walletInstance = new CWallet(std::move(dbw));
 RegisterValidationInterface(walletInstance);
 ......
 }

在submitblock rpc调用中, 用户提交hex编码的原始block, 解析后, 调用ProcessNewBlock()检查处理,使用类型submitblock_StateCatcher 的对象sc 作为MainSignalsInstance 的订阅者,
对提交过去的block 的验证结果,作为事件通知返回给rpc 调用。

UniValue submitblock(const JSONRPCRequest& request)
 {
 ...........
 submitblock_StateCatcher sc(block.GetHash());
 RegisterValidationInterface(&sc);
 bool fAccepted = ProcessNewBlock(Params(), blockptr, true, nullptr);
 UnregisterValidationInterface(&sc);
 ...........
 }

CMainSignals 类型上面定义了一堆触发事件的方法, 别的代码模块调用这些方法, 触发相应的事件,把事件通知发给相关的订阅者。

void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
 m_internals->m_schedulerClient.AddToProcessQueue([pindexNew, pindexFork, fInitialDownload, this] {
 m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
 });
 }
 void CMainSignals::TransactionAddedToMempool(const CTransactionRef &ptx) {
 m_internals->m_schedulerClient.AddToProcessQueue([ptx, this] {
 m_internals->TransactionAddedToMempool(ptx);
 });
 }
 void CMainSignals::BlockConnected(const std::shared_ptr &pblock, const CBlockIndex *pindex, const std::shared_ptr>& pvtxConflicted) {
 m_internals->m_schedulerClient.AddToProcessQueue([pblock, pindex, pvtxConflicted, this] {
 m_internals->BlockConnected(pblock, pindex, *pvtxConflicted);
 });
 }
 void CMainSignals::BlockDisconnected(const std::shared_ptr &pblock) {
 m_internals->m_schedulerClient.AddToProcessQueue([pblock, this] {
 m_internals->BlockDisconnected(pblock);
 });
 }
 void CMainSignals::SetBestChain(const CBlockLocator &locator) {
 m_internals->m_schedulerClient.AddToProcessQueue([locator, this] {
 m_internals->SetBestChain(locator);
 });
 }
 void CMainSignals::Inventory(const uint256 &hash) {
 m_internals->m_schedulerClient.AddToProcessQueue([hash, this] {
 m_internals->Inventory(hash);
 });
 }
 void CMainSignals::Broadcast(int64_t nBestBlockTime, CConnman* connman) {
 m_internals->Broadcast(nBestBlockTime, connman);
 }
 void CMainSignals::BlockChecked(const CBlock& block, const CValidationState& state) {
 m_internals->BlockChecked(block, state);
 }
 void CMainSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr &block) {
 m_internals->NewPoWValidBlock(pindex, block);
 }

CChainState 的ActivateBestChain方法里, 发布BlockConnected, UpdatedBlockTip 事件:

bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr pblock) {
 ..............................
 for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) {
 assert(trace.pblock && trace.pindex);
 GetMainSignals().BlockConnected(trace.pblock, trace.pindex, trace.conflictedTxs);
 }
 ..............................
 GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
 ...............................
 }

CChainState 的AcceptBlock 方法里,发布NewPoWValidBlock 事件:

bool CChainState::AcceptBlock(const std::shared_ptr& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock)
 {
 .......................
 if (!IsInitialBlockDownload() && chainActive.Tip() == pindex->pprev)
 GetMainSignals().NewPoWValidBlock(pindex, pblock);
 ......................
 }

CChainState 的DisconnectTip 方法里,发布 BlockDisconnected 事件:

bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool)
 {
 ...................
 GetMainSignals().BlockDisconnected(pblock);
 ..............
 }

CChainState 的ConnectTip 方法里,发布 BlockChecked 事件:

bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool)
 {
 ................
 CCoinsViewCache view(pcoinsTip.get());
 bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, chainparams);
 GetMainSignals().BlockChecked(blockConnecting, state);
 ................
 }

PeerLogicValidation 的 SendMessage 方法里, 发布Broadcast事件, 通知钱包重新发送未确认的交易:

bool PeerLogicValidation::SendMessages(CNode* pto, std::atomic& interruptMsgProc)
 {
 .............
 if (!fReindex && !fImporting && !IsInitialBlockDownload())
 {
 GetMainSignals().Broadcast(nTimeBestReceived, connman);
 }
 .............
 }

从网络上收到INV消息后,通知给钱包,更新内部状态。

bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic& interruptMsgProc)
 {
 .................
 for (CInv &inv : vInv)
 {
 ............
 GetMainSignals().Inventory(inv.hash);
 }
 ................
 }

validation.cpp 里面的 ProcessNewBlock在内部调用 CheckBlock 后,检查失败后,发布 BlockCheck s事件, 通告给相关订阅者。

bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr pblock, bool fForceProcessing, bool *fNewBlock)
 {
 ............
 bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus());
 if (!ret) {
 GetMainSignals().BlockChecked(*pblock, state);
 return error("%s: AcceptBlock FAILED (%s)", __func__, state.GetDebugMessage());
 }
 ...........
 }

FlushStateToDisk, 发布SetBestChain 事件, 通知钱包

bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight) {
 ...............
 if (fDoFullFlush || ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) {
 // Update best block in wallet (so we can detect restored wallets).
 GetMainSignals().SetBestChain(chainActive.GetLocator());
 nLastSetChain = nNow;
 }
 ...............
 }

validation.cpp 里面的AcceptToMemoryPoolWorker, 在结束前, 发布TransactionAddedToMempool 事件。

static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx,
 bool* pfMissingInputs, int64_t nAcceptTime, std::list* plTxnReplaced,
 bool bypass_limits, const CAmount& nAbsurdFee, std::vector& coins_to_uncache)
 {
 ................
 GetMainSignals().TransactionAddedToMempool(ptx);
 }
boost源码剖析之:多重回调机制signal(上) boost源码剖析之:多重回调机制signal(上) 刘未鹏C++的罗浮宫(http://blog.youkuaiyun.com/pongba) boost库固然是技术的宝库,却更是思想的宝库。大多数程序员都知道如何应用command,observer等模式,却不知该如何写一个支持该模式的类。正如隔靴搔痒,无法深入。DDJ上曾有一篇文章用C++实现类似C#的event机制,不过是个雏形,比 阅读详情

相关推荐

boost源码剖析之:多重回调机制signal(下)

boost源码剖析之:多重回调机制signal(下) 刘未鹏C++的罗浮宫(http://blog.youkuaiyun.com/pongba) 在本文的上篇中,我们大刀阔斧的剖析了signal的架构。不过还有很多精微之处没有提到,特别是一个遗留问题还没有解决:如果用户注册的是函数对象(仿函数),signal又当如何处理呢? 下篇:高级篇概述在本文的上篇中,我们已经分析了s

刘未鹏|C++的罗浮宫 1万+

c++ 中的事件机制 boost signal

c#的事件用起来多方便,c++没有现成的,boost signal 倒是比较方便: 以下是转载: https://blog.youkuaiyun.com/zengraoli/article/details/9697841 signals2基于Boost的另一个库signals,实现了线程安全的观察者模式。在signals2库中,观察者模式被称为信号/插槽(signals and slots),他是一种函数回调机制,一个信号关联了多个插槽,当信号发出时,所有关联它的插槽都会被调用。 许多成熟的软件系统都用到.

HETONGDE的博客 1102

【BOOST C++ 20 设计模式】(2)库Boost.Signals2

Boost.Signals2 实现了信号/槽的概念。一个或多个函数(称为槽)与可以发出信号的对象相关联。每次发出信号时,都会调用链接的函数。

gongdiwudu的专栏 5720

Boost教程之事件处理

很多开发者在听到术语'事件处理'时就会想到GUI:点击一下某个按钮,相关联的功能就会被执行。 点击本身就是事件,而功能就是相对应的事件处理器。这一模式的使用当然不仅限于GUI。 一般情况下,任意对象都可以调用基于特定事件的专门函数。 1、信号 Signals Boost.Signals 库提供了一个名为 boost::signal 的类,定义于 boost/signal.hpp. 实际上,这...

王木木 789

使用Boost.Signals实现信号和槽机制

在C++编程中,信号和槽机制是一种非常便捷的交互式程序设计方法。Boost.Signals是一个开源的C++第三方库,它提供了信号和槽机制的实现。通过使用Boost.Signals,我们可以非常容易地创建对象之间的通信机制。以上就是使用Boost.Signals实现信号和槽机制的简单示例。通过使用信号和槽机制,我们可以更方便地实现对象之间的通信,使程序变得更加模块化。本文将介绍如何使用Boost.Signals实现信号和槽机制。使用Boost.Signals实现信号和槽机制。

2301_79365003的博客 449

boost::signals2模块thread_safe_signals 库替代线程模型的基本测试

boost::signals2模块thread_safe_signals 库替代线程模型的基本测试实现功能C++实现代码 实现功能 boost::signals2模块thread_safe_signals 库替代线程模型的基本测试 C++实现代码 #include <boost/signals2.hpp> #define BOOST_TEST_MODULE threading_models_test #include <boost/test/included/unit_test.hpp&g

希望我的博客,能帮上你解决学习中工作中所遇到的问题 556

boost::signal2

// 忽略警告 #define _SCL_SECURE_NO_WARNINGS #pragma warning(disable : 4996) #include <assert.h> #include <iostream> #include <boost/signals2/signal.hpp> #include <boost/signals2/shar...

weixin_38850997的博客 250

boost::signals2::signal_type相关的测试程序

boost::signals2::signal_type相关的测试程序实现功能C++实现代码 实现功能 boost::signals2::signal_type相关的测试程序 C++实现代码 #include <boost/signals2.hpp> #define BOOST_TEST_MODULE signal_type_test #include <boost/test/included/unit_test.hpp> namespace bs2 = boost::signals

希望我的博客,能帮上你解决学习中工作中所遇到的问题 586

boost::signals::signal的用法

吃力的讲完boost::signals的ppt,然后接着就是做练习题。通过讲ppt,发现有一句话说的真好:你自己知道是一回事,你能给别人讲明白又是另外一回事。真的有些东西你自己理解,但是用语言去很难表达,是不是用语言难以表达暴露出自己对所理解的东西不是真正的理解?。。。。orz,不过讲完ppt之后,真的对boost::singals的理解又加深一层。好了废话不多说了,现在来看两个习题(ppt的内容

yanziguilai的专栏 3574

boost::signals2库中的signal_type测试程序

需要注意的是,signal_type类型的定义方式为boost::signals2::signal,其中void ()表示信号没有参数。在使用boost::signals2库时,我们会用到signal_type类型,它表示信号对象的类型。总之,boost::signals2库中的signal_type类型非常重要,它是信号和槽机制的核心之一。通过编写了上述的测试程序,我们可以更好地理解signal_type类型的作用和使用方式,也可以更加灵活地应用boost::signals2库。

DevCharm的博客 219

决策规划算法四:Piecewise Jerk Path Optimizer

一,问题分析 路径规划的本质目的:规划出一条安全(无碰撞),舒适(平滑),符合车辆运动学的轨迹。 如下图所示,决策算法开辟凸空间后,路径规划算法用数值优化的方法搜索出一条最优路径,即将问题转化为二次规划的问题,采用二次规划的求解器进行求解。 二次规划问题的求解顺序: 1,确定优化变量 2,确定目标函数 3,确定约束条件 4,将目标函数和约束条件变形为二次规划的标准形式 5,用二次规划求解器进行求解,获得优化变量的序列,使得目标函数取得最小值。 注:路径的最终表达式为:,..

肥嘟嘟的左卫门 8560

boost asio::signal_set用法

signal_set signal_set提供了一个信号,方便异步处理程序,比如设置了SIGINT信号,程序中断先连接一个函数,如果触发了中断这个信号就会触发这个函数。 基本用法 asio::io_service service; asio::signal_set sigset(service); m_signals.add(SIGINT); //添加信号,remove删除 sigset.async_wait(signal_handler); //设置触发函数 sigset.async_wait(

caicaptain 2906

自建邮局服务器| 批量邮件群发系统PowerMTA+oem(mumara,mailwizz, interspire)

世界顶级自建邮局服务器PowerMTA+oem(mumara,mailwizz, interspire) PowerMTA4.5(最好用的 群发邮件软件)是用于大批量多ip开发的邮件传递邮寄。可按每小时发送数近百万条电子邮件,发送IP地址和域可以详细配置,加上目前流行前端oem,mumara,mailwizz, interspire等,可定时发送,定时重复发送,实现全自动化 邮件群发 方案。 官网(powermta4.5下载) https://www.sparkpost.com/powermta/ 使用Po

ytrsexpo的博客 6501

boost:asio信号量signal_set源码分析及使用

首先我们先看signal_set.hpp,可以看到下面代码#include <boost/asio/detail/config.hpp> #include <boost/asio/basic_signal_set.hpp>namespace boost { namespace asio {/// Typedef for the typical usage of a signal set. typed

YiShi's Blog 5521

3DE重客户端安装

3DE重客户端安装

m0_48170265的博客 9420

【UE4】PMC程序化生成戈德堡多面体详解(六边形星球)

游戏实机录屏 【魔方超新星】30天独立开发PCG Minigame《盖亚计划》作品展示,尚有不足,大佬轻喷 目录 游戏实机录屏 一、简介 二、设计思路 2.1 Disco Ball 2.2 Fibonacci Sphere 2.3 Goldberg Polyhedron 2.3.1 细分+对偶(最终方案) 2.3.2 对偶+截角(更优) 三、参考文献 一、简介 在制作Minigame初期,游戏风格想模仿《文明6》与《Polygonal Planet Proje...

ColorGalaxy 5928

boost:signal_set异步处理信号

信号(signal)是UNIX系统中的一种常用的进程间异步通信机制。asio提供了类signal_set,利用异步IO的方式处理UNIX信号。

OceanStar的博客 776

OpenCV图像去畸变实战指南:从原理到参数调优(附完整代码与效果对比)

本文详细解析了OpenCV图像去畸变的原理与实战方法,对比了三种核心函数(标准、鱼眼、全景模型)的适用场景与效果。重点提供了完整的代码示例,并深入探讨了alpha、焦距、中心点等关键参数的调优技巧,以帮助开发者有效矫正镜头畸变,提升计算机视觉任务精度。

life6的博客 553

boost源码剖析之:多重回调机制signal

刘未鹏C++的罗浮宫(http://blog.youkuaiyun.com/pongba) boost库固然是技术的宝库,却更是思想的宝库。大多数程序员都知道如何应用command,observer等模式,却不知该如何写一个支持该模式的类。正如隔靴搔痒,无法深入。DDJ上曾有一篇文章用C++实现类似C#的event机制,不过是个雏形,比之boost.Signal却又差之甚远矣。 上篇:架构

痞子龙3D编程 1863

基于 DnLUT 超高效的彩色图像去噪(CVPR 2025),本地部署 DnLUT 模型,图像去噪算法训练和推理,全网最详细教程

基于 DnLUT 超高效的彩色图像去噪(CVPR 2025),本地部署 DnLUT 模型,图像去噪算法训练和推理,全网最详细教程

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 363

uniapp中使用canvas生成海报,并下载保存到手机相册

如下图,是在H5中,canvas生成后的效果,首先说明,H5不支持返回图片的临时路径,不能用于保存,APP端生成成功后,会返回图片的临时路径用来保存到相册。本地测试,用的网络图片,没有出现跨域的问题,APP端也正常显示。 完整代码:可以将整个代码复制到你得uniapp项目中直接运行。代码中做了详细的注册,关于API的用法,这里只标注的简单的提示,具体还是参考 官方链接uniapp-canvas吧 <template> <view class="demo"> <c.

sunluyi的博客 3万+

boost::signals::signal的使用方法

吃力的讲完boost::signals的ppt。然后接着就是做练习题。通过讲ppt,发现有一句话说的真好:你自己知道是一回事。你能给别人讲明确又是另外一回事。真的有些东西你自己理解,可是用语言去非常难表达,是不是用语言难以表达暴露出自己对所理解的东西不是真正的理解?。。。。orz。只是讲完ppt之后,真的对boost::singals的理解又加深一层。好了废话不多说了,如今来看两个习题(p...

weixin_30599769的博客 358

Response Instance 详解:在 ABAP OData Client Proxy 中读懂每一次响应

ABAP OData Client Proxy中的Response Instance是关键信息载体,封装了业务数据及调用上下文(如分页、delta link等)。响应实例在执行请求后自动生成,根据请求类型返回特定接口(如READ返回/IWBEP/IF_CP_RESPONSE_READ)。响应抽象与OData版本解耦,支持统一处理V2/V4服务。常见响应类型包括单实体读取、列表读取(支持分页和增量同步)、创建/更新/删除响应等。开发时可通过响应对象的安全类型方法获取数据,如get_business_data获

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 136
上一篇: 任务调度器
下一篇: CMessageHeader
TuxedoLinux
博客等级 码龄9年 268粉丝 34原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值