C ++ã§ä¿¡å·ãå®è£
ããã©ã€ãã©ãªã¯äžçäžã«ãããããããŸãã æ®å¿µãªãããç§ãééãããã¹ãŠã®å®è£
ã«ã¯ããããã®ã©ã€ãã©ãªã䜿çšããŠåçŽãªãã«ãã¹ã¬ããã³ãŒããæžãããšã劚ããããã€ãã®åé¡ããããŸãã ããã§ã¯ããããã®åé¡ãšãã®è§£æ±ºæ¹æ³ã«ã€ããŠèª¬æããŸãã
ã·ã°ãã«ãšã¯äœã§ããïŒ
å€ãã®äººã¯ãã§ã«ãã®æŠå¿µã«ç²ŸéããŠãããšæããŸããã念ã®ããããããæžããŸãã
ã·ã°ãã«ã¯ãä»»æã®ã€ãã³ãã®éç¥ããäºãã«ç¬ç«ããŠç»é²ã§ããåä¿¡è
ã«éä¿¡ããæ¹æ³ã§ãã å¿
èŠã«å¿ããŠãå€ãã®åä¿¡è
ãšã³ãŒã«ããã¯ããŸãã ãŸãã¯ã.NETããã«ããã£ã¹ãããªã²ãŒãã§äœæ¥ãã人åãã
boost :: signals2ã䜿çšããããã€ãã®äŸä¿¡å·ã®çºè¡šïŒ
struct Button { boost::signals2::signal<void()> OnClick; };
ä¿¡å·ãžã®æ¥ç¶ãšä¿¡å·ããã®åæïŒ
void ClickHandler() { cout << âButton clickedâ << endl; }
ã·ã°ãã«ã³ãŒã«ïŒ
struct Button { boost::signals2::signal<void()> OnClick; private: void MouseDownHandler() { OnClick(); } };
åé¡ã«ã€ããŠ
ã·ã³ã°ã«ã¹ã¬ããã®ã³ãŒãã§ã¯ããã¹ãŠãçŽ æŽãããèŠããããªãããŸãæ©èœããŸããããã«ãã¹ã¬ããã®å Žåã¯ã©ãã§ããããïŒ
æ®å¿µãªãããç°ãªãå®è£
ã«å
±éãã3ã€ã®åé¡ããããŸãã
- ã¢ãããã¯ã«ä¿¡å·ã«æ¥ç¶ããŠãã€ã³ããããç¶æ
ãååŸããæ¹æ³ã¯ãããŸãã
- ä¿¡å·ããã®ãã³ããããã³ã°åæ
- éåæãã³ãã©ãŒãç¡å¹ã«ããŠãããã§ã«ã¹ã¬ãããã¥ãŒã«ããåŒã³åºãã¯ãã£ã³ã»ã«ãããŸããã
ããããã詳现ã«æ€èšããŸãããã ãããè¡ãããã«ãæ¶ç©ºã®ã¡ãã£ã¢ã»ãããããããã¯ã¹ã®ãã¡ãŒã ãŠã§ã¢éšåãã€ãŸã3ã€ã®ã¯ã©ã¹ãäœæããŸãã
- StorageManager-ãã©ãã·ã¥ãã©ã€ããDVDãããã³ãŠãŒã¶ãŒãã³ã³ãœãŒã«ã«æ¿å
¥ãããã®ä»ã®ã¡ãã£ã¢ã«å¿çããã¯ã©ã¹
- MediaScanner-ãããã®åããã€ã¹ã§ã¡ãã£ã¢ãã¡ã€ã«ãæ€çŽ¢ããã¯ã©ã¹
- MediaUiModel-ãããã®ã¡ãã£ã¢ãã¡ã€ã«ãæ¶ç©ºã®Model-View-anythingãã¬ãŒã ã¯ãŒã¯ã§è¡šç€ºããããã®ã¢ãã«
ããã§è¡šç€ºãããã³ãŒãã¯éåžžã«åçŽåãããŠããããããã®åé¡ã«éäžã§ããããã«ãäœåãªãã®ã¯äžåå«ãŸããŠããŸããã ã¿ã€ã
TypePtrã®ã¿ã€ãã衚瀺ãããŸãã ããã¯åãªã
std :: shared_ptr <Type>ã§ãã ãå¿é
ããªãã§ãã ããã
ã¢ãããã¯ã«ä¿¡å·ã«æ¥ç¶ããŠãã€ã³ããããç¶æ
ãååŸããæ¹æ³ã¯ãããŸãã
ã ããã
StorageManager ã ãã§ã«ã³ã³ãœãŒã«ã«æ¿å
¥ãããŠããã¡ãã£ã¢ã®ã²ãã¿ãŒãšãæ°ããã¡ãã£ã¢ãéç¥ããä¿¡å·ãå¿
èŠã§ãã
class StorageManager { public: std::vector<StoragePtr> GetStorages() const; boost::signals2::signal<void(const StoragePtr&)> OnStorageAdded;
æ®å¿µãªããããã®ãããªã€ã³ã¿ãŒãã§ã€ã¹ã¯ç«¶åç¶æ
ãçºçããªãéã䜿çšã§ããŸããã
ãã®é åºã§ã¯æ©èœããŸãã...
storageManager->OnStorageAdded.connect(&StorageHandler);
...ãããŠããã®é åºã§ã¯æ©èœããŸããã
for (auto&& storage : storageManager->GetStorages()) StorageHandler(storage);
å
±éã®è§£æ±ºç
æããã«ã競åç¶æ
ã«ãªã£ãããããã¥ãŒããã¯ã¹ãå¿
èŠã§ãã
class StorageManager { mutable std::recursive_mutex _mutex; std::vector<StoragePtr> _storages; public: StorageManager() { } boost::signals2::signal<void(const StoragePtr&)> OnStorageAdded; std::recursive_mutex& GetMutex() const { return _mutex; } std::vector<StoragePtr> GetStorages() const { std::lock_guard<std::recursive_mutex> l(_mutex); return _storages; } private: void ReportNewStorage(const StoragePtr& storage) { std::lock_guard<std::recursive_mutex> l(_mutex); _storages.push_back(storage); OnStorageAdded(storage); } };
ãã®ã³ãŒãã¯æ©èœããŸãããããã€ãã®æ¬ ç¹ããããŸãã
- std :: recursive_mutexã®ä»£ããã«std :: mutexã䜿çšããå Žåã GetStoragesã¡ãœããå
ã§ããããã£ããã£ããæ©èœã倱ããã StorageManagerã¯ã©ã¹ãéã¹ã¬ããã»ãŒãã«ãªããŸãã
- StorageManagerã®ã¹ã¬ããã»ãŒãã倱ãããšãªãã GetStorageså
ã®ã³ã¬ã¯ã·ã§ã³ã®ã³ããŒãåãé€ãããšã¯ã§ããŸããã
- ã¿ã€ãstd :: vector <StoragePtr> outsideã衚瀺ããå¿
èŠããããŸãããå®éã«ã¯ãããã¯å®è£
ã®è©³çŽ°ã«ãããŸãã
- ä¿¡å·ã«æ¥ç¶ããŠçŸåšã®ç¶æ
ãåä¿¡ããããã®ããªã倧éã®ã³ãŒãããã®å Žåãããã¯ç°ãªãä¿¡å·ã«å¯ŸããŠã»ãŒåãã§ãã
ããè¯ãæ¹æ³ã¯ïŒ
connectåŒã³åºãïŒmutexãååŸããŠã³ã¬ã¯ã·ã§ã³ãèµ°æ»ããïŒã®åšãã§è¡ããã¹ãŠãå
éšã«è»¢éããŸãããã
çŸåšã®ç¶æ
ãååŸããã¢ã«ãŽãªãºã ã¯ããã®ç¶æ
èªäœã®æ§è³ªã«äŸåããããšãç解ããããšãéèŠã§ãã ãããã³ã¬ã¯ã·ã§ã³ã§ããå ŽåãåèŠçŽ ã®ãã³ãã©ãŒãåŒã³åºãå¿
èŠããããŸããããšãã°ãenumã®å Žåã¯ããã³ãã©ãŒã1åã ãåŒã³åºãå¿
èŠããããŸãã ãããã£ãŠãæœè±¡åãå¿
èŠã§ãã
ã·ã°ãã«ã«
ããã¥ã¬ãŒã¿ãŒãè¿œå ããŸããããã¯ãçŸåšæ¥ç¶ãããŠãããã³ãã©ãŒãåãå
¥ããé¢æ°ã§ãã·ã°ãã«ã®ææè
ïŒãã®å Žåã¯StorageManagerïŒã«çŸåšã®ç¶æ
ããã®ãã³ãã©ãŒã«éä¿¡ããæ¹æ³ã決å®ãããŸãã
template < typename Signature > class signal { using populator_type = std::function<void(const std::function<Signature>&)>; mutable std::mutex _mutex; std::list<std::function<Signature> > _handlers; populator_type _populator; public: signal(populator_type populator) : _populator(std::move(populator)) { } std::mutex& get_mutex() const { return _mutex; } signal_connection connect(std::function<Signature> handler) { std::lock_guard<std::mutex> l(_mutex); _populator(handler);
signal_connectionã¯ã©ã¹ã¯
çŸåš ãã·ã°ãã«å
ã®ãªã¹ããããã³ãã©ãŒãåé€ããã©ã ãé¢æ°ãåãå
¥ããŸãã åŸã§ããå°ãå®å
šãªã³ãŒããæäŸããŸãã
ãã®æ°ããæŠå¿µã䜿çšããŠã
StorageManagerãæžãæã
ãŸã ã
class StorageManager { std::vector<StoragePtr> _storages; public: StorageManager() : _storages([&](const std::function<void(const StoragePtr&)>& h) { for (auto&& s : _storages) h(s); }) { } signal<void(const StoragePtr&)> OnStorageAdded; private: void ReportNewStorage(const StoragePtr& storage) {
C ++ 14ã䜿çšããå Žåãããã¥ã¬ãŒã¿ãŒã¯éåžžã«çããªããŸãã
StorageManager() : _storages([&](auto&& h) { for (auto&& s : _storages) h(s); }) { }
ããã¥ã¬ãŒã¿ãŒãåŒã³åºããããšããã¥ãŒããã¯ã¹ã¯
signal :: connectã¡ãœããã§ãã£ããã£ããããããããã¥ã¬ãŒã¿ãŒã®æ¬äœã§ã¯å¿
èŠãªãããšã«æ³šæããŠãã ããã
ã¯ã©ã€ã¢ã³ãã³ãŒãã¯éåžžã«çããªããŸãã
storageManager->OnStorageAdded.connect(&StorageHandler);
1è¡ã§ãåæã«ä¿¡å·ã«æ¥ç¶ãããªããžã§ã¯ãã®çŸåšã®ç¶æ
ãååŸããŸãã ãããïŒ
ä¿¡å·ããã®ãã³ããããã³ã°åæ
ããã§ã
MediaScannerãäœæããŸãã ã³ã³ã¹ãã©ã¯ã¿ãŒã§ãã·ã°ãã«
StorageManager :: OnStorageAddedã«æ¥ç¶ãããã¹ãã©ã¯ã¿ãŒã§åæããŸãã
class MediaScanner { private: boost::signals2::connection _connection; public: MediaScanner(const StorageManagerPtr& storageManager) { _connection = storageManager->OnStorageAdded.connect([&](const StoragePtr& s) { this->StorageHandler(s); }); } ~MediaScanner() { _connection.disconnect();
æ²ããããªããã®ã³ãŒãã¯æã
èœã¡ãã§ãããã ãã®çç±ã¯ãç§ãç¥ã£ãŠãããã¹ãŠã®å®è£
ã§ã
disconnectã¡ãœãããã©ã®ããã«æ©èœãããã§ãã 次åã·ã°ãã«ãåŒã³åºããããšãã«ã察å¿ãããã³ãã©ãŒãæ©èœããªãããšãä¿èšŒããŸãã ãã®å Žåããã®æç¹ã§ãã³ãã©ãŒãå¥ã®ã¹ã¬ããã§å®è¡ããããšããã³ãã©ãŒã¯äžæããããç Žæ£ããã
MediaScannerãªããžã§ã¯ãã§åŒãç¶ãåäœããŸãã
Qtã®ãœãªã¥ãŒã·ã§ã³
Qtã§ã¯ããã¹ãŠã®ãªããžã§ã¯ãã¯ç¹å®ã®ã¹ã¬ããã«å±ãããã®ãã³ãã©ãŒã¯ãã®ã¹ã¬ããã§æä»çã«åŒã³åºãããŸãã ã·ã°ãã«ããå®å
šã«åæããã«ã¯ã
QObject :: deleteLaterã¡ãœãããåŒã³åºããŠãç®çã®ã¹ã¬ããããå®éã®åé€ãè¡ãããåé€åŸã«ãã³ãã©ãŒãåŒã³åºãããªãããã«ããŸãã
mediaScanner->deleteLater();
ããã¯ãQtãšå®å
šã«çµ±åããæºåãã§ããŠããå Žåã«é©ãããªãã·ã§ã³ã§ãïŒããã°ã©ã ã®ã³ã¢ã§ã¯std :: threadãæŸæ£ããŠãQObjectãQThreadãªã©ãåªå
ããŸãïŒã
Boostã®ãœãªã¥ãŒã·ã§ã³:: Signals2
ãã®åé¡ã解決ããããã«ã
boostã§ã¯ãã¹ãããïŒã€ãŸããã³ãã©ãŒïŒã§
track /
track_foreignã¡ãœããã䜿çšããããšãã
å§ãããŸã ã ãããã®ã¡ãœããã¯ä»»æã®ãªããžã§ã¯ãã«å¯ŸããŠ
weak_ptrã䜿çšããåãªããžã§ã¯ããçããŠããéããã³ãã©ãŒãšã·ã°ãã«ã®æ¥ç¶ãååšããã¹ãããã¯ããããç£èŠãããŸãã
ããã¯éåžžã«ç°¡åã«æ©èœããŸããåã¹ãããã«ã¯ãç£èŠå¯Ÿè±¡ãªããžã§ã¯ãã®
weak_ptrã®ã³ã¬ã¯ã·ã§ã³ãããããã³ãã©ã®æéäžãããã¯ãïŒç³ãèš³ãããŸããïŒããŸãã ãããã£ãŠããããã®ãªããžã§ã¯ãã¯ããã³ãã©ãŒã³ãŒããã¢ã¯ã»ã¹ã§ããéããç Žæ£ãããããšã¯ä¿èšŒãããŠããŸããã ãªããžã§ã¯ãã®ããããããã§ã«ç Žæ£ãããŠããå Žåãæ¥ç¶ã¯åæãããŸãã
åé¡ã¯ããã®ããã«ã眲åããããªããžã§ã¯ãã«
weak_ptrãå¿
èŠã§ãããšããããšã§ãã ç§ã®æèŠã§ã¯ããããå®çŸããæãé©åãªæ¹æ³ã¯ã
MediaScannerã¯ã©ã¹ã§ãã¡ã¯ããªã¡ãœãããäœæããããšã§ãããã®ã¡ãœããã§ã¯ãäœæãããªããžã§ã¯ãã«ãé¢å¿ã®ãããã¹ãŠã®ä¿¡å·ã«çœ²åããŸãã
class MediaScanner { public: static std::shared_ptr<MediaScanner> Create(const StorageManagerPtr& storageManager) { std::lock_guard<std::recursive_mutex> l(storageManager->GetMutex()); MediaScannerPtr result(new MediaScanner); boost::signals2::signal<void(const StoragePtr&)>::slot_type slot(bind(&MediaScanner::StorageHandler, result.get(), _1)); slot.track_foreign(result); storageManager->OnStorageAdded.connect(slot); for (auto&& storage : storageManager->GetStorages()) result->StorageHandler(storage); return result; } private: MediaScanner()
ãããã£ãŠãæ¬ ç¹ã¯æ¬¡ã®ãšããã§ãã
- ãããæ¯åã³ããŒããããããã®ã³ãŒã
- MediaScannerã®åæå㯠2ã€ã®éšåã«åãããŠããŸããCreateã¡ãœããã§ã·ã°ãã«ããµãã¹ã¯ã©ã€ãããããšãããã³ã³ã³ã¹ãã©ã¯ã¿ãŒã§ä»ã®ãã¹ãŠããµãã¹ã¯ã©ã€ãããããšã§ãã
- MediaScannerãä¿åããã«ã¯shared_ptrã䜿çšããå¿
èŠããããŸã
- MediaScannerãžã®æåŸã®å€éšãªã³ã¯ããªãªãŒã¹ãããšãã«MediaScannerãåé€ããããã©ããã¯ããããŸããã MediaScannerã®ãªãªãŒã¹åŸã«åå©çšãããéããããªãœãŒã¹ã䜿çšããå Žåãããã¯åé¡ã«ãªãå¯èœæ§ããããŸãã
ããè¯ãæ¹æ³ã¯ïŒ
disconnectã¡ãœãããããã¯ãäœæããŠãã³ã³ãããŒã«ãè¿ããåŸãã·ã°ãã«ãã³ãã©ãã¢ã¯ã»ã¹ãããã¹ãŠã®ãã®ãç Žæ£ã§ããããšãä¿èšŒããŸãã
std :: thread :: joinã¡ãœããã®ãããªãã®ã
ä»åŸã¯ããã®ããã«3ã€ã®ã¯ã©ã¹ãå¿
èŠã ãšèšããŸãã
- life_token-ãã³ãã©ãŒã®åç¶æéãå¶åŸ¡ãããã³ãã©ãŒããæ»ãã§ããããšããŒã¯ããå¿
èŠã«å¿ããŠå®è¡ã®çµäºãåŸ
ã€ããšãã§ããŸã
- life_token ::ãã§ãã«ãŒ -ãã³ãã©ãŒã®é£ã®ã·ã°ãã«å
ã«æ ŒçŽããããã®life_tokenãåç
§ããŸã
- life_token :: checker :: execution_guard-ãã³ãã©ãŒã®å®è¡äžã«ã¹ã¿ãã¯äžã«äœæããã察å¿ããlife_tokenããããã¯ãããã³ãã©ãŒãæ©ããæ»ãã ããã©ããã確èªã§ããŸã
ã³ãŒãã¯ã©ã¹
signal_connection ïŒ
class signal_connection { life_token _token; std::function<void()> _eraseHandlerFunc; public: signal_connection(life_token token, std::function<void()> eraseHandlerFunc) : _token(token), _eraseHandlerFunc(eraseHandlerFunc) { } ~signal_connection(); { disconnect(); } void disconnect() { if (_token.released()) return; _token.release();
ããã§ç§ã¯RAIIæ¥ç¶ãªããžã§ã¯ãã®ãµããŒã¿ãŒã§ãããšèšããªããã°ãªããŸããã ããã«ã€ããŠã¯è©³ãã説æããŸãããããã®æèã§ã¯éèŠã§ã¯ãªããšããèšââããŸããã
ä¿¡å·ã¯ã©ã¹ãå°ãå€æŽãããŸãïŒ
template < typename Signature > class signal { using populator_type = std::function<void(const std::function<Signature>&)>; struct handler { std::function<Signature> handler_func; life_token::checker life_checker; }; mutable std::mutex _mutex; std::list<handler> _handlers; populator_type _populator; public:
ããŠãåãã³ãã©ã®æšªã«ã
signal_connectionã«ãã
life_tokenãåç
§ãã
life_token :: checkerãªããžã§ã¯ãããããŸãã ãªããžã§ã¯ã
life_token :: checker :: execution_guardã䜿çšããŠããã³ãã©ãŒã®æéäžã«ãã£ããã£ããŸã
ãããã®ãªããžã§ã¯ãã®å®è£
ããã¿ãã¬ã®äžã«é ããŸãã ç²ããŠããå Žåã¯ãã¹ãããã§ããŸããlife_tokenå
ã§ã¯ã次ã®ãã®ãå¿
èŠã§ãã
- life_token :: releaseã§åŸ
æ©ããããçš®ã®ããªããã£ããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ïŒããã§ã¯ãç°¡åã«ããããã«mutexã䜿çšããŸãïŒ
- ã©ã€ã/ããããã©ã°
- execution_guardã«ããããã¯ã«ãŠã³ã¿ãŒïŒç°¡åã«ããããã«ããã§ã¯çç¥ïŒ
class life_token { struct impl { std::mutex mutex; bool alive = true; }; std::shared_ptr<impl> _impl; public: life_token() : _impl(std::make_shared<impl>()) { } ~life_token() { release(); } bool released() const { return !_impl; } void release() { if (released()) return; std::lock_guard<std::mutex> l(_impl->mutex); _impl->alive = false; _impl.reset(); } class checker { shared_ptr<impl> _impl; public: checker(const life_token& t) : _impl(t._impl) { } class execution_guard { shared_ptr<Impl> _impl; public: execution_guard(const checker& c) : _impl(c._impl) { _impl->mutex.lock(); } ~execution_guard() { _impl->mutex.unlock(); } bool is_alive() const { return _impl->alive; } }; }; };
ãã¥ãŒããã¯ã¹ã¯ã
execution_guardã©ã€ãã¿ã€ã ã®éãã£ããã£ãããŸãã ãããã£ãŠããã®æç¹ã§
life_token :: releaseã¡ãœãããå¥ã®ã¹ã¬ããã§åŒã³åºãããå Žåãåãmutexã®ãã£ããã£ã§ãããã¯ãããã·ã°ãã«ãã³ãã©ãŒã®å®è¡ãå®äºãããŸã§åŸ
æ©ããŸãã ãã®åŸã
çããŠãããã©ã°ãã¯ãªã¢ããã·ã°ãã«ãžã®ä»¥éã®ãã¹ãŠã®åŒã³åºãã¯ãã³ãã©ãŒã®åŒã³åºãã«ã€ãªãããŸããã
MediaScannerã³ãŒãã¯çŸåšã©ã®ããã«èŠããŸããïŒ ãŸãã«æåã«ãããæžãããã£ãæ¹æ³ïŒ
class MediaScanner { private: signals_connection _connection; public: MediaScanner(const StorageManagerPtr& storageManager) { _connection = storageManager->OnStorageAdded.connect([&](const StoragePtr& s) { this->StorageHandler(s); }); } ~MediaScanner() { _connection.disconnect(); } private: void StorageHandler(const StoragePtr& storage) { } };
éåæãã³ãã©ãŒãç¡å¹ã«ããŠãããã§ã«ã¹ã¬ãããã¥ãŒã«ããåŒã³åºãã¯ãã£ã³ã»ã«ãããŸããã
èŠã€ãã£ãã¡ãã£ã¢ãã¡ã€ã«ã«å¿çãããããã衚瀺ããè¡ãè¿œå ãã
MediaUiModelãäœæããŸãã
ãããè¡ãã«ã¯ã次ã®ä¿¡å·ã
MediaScannerã«è¿œå ããŸãã
signal<void(const MediaPtr&)> OnMediaFound;
ããã«ã¯2ã€ã®éèŠãªããšããããŸãã
- ã¢ãã«ã¯UIã©ã€ãã©ãªã®ãªããžã§ã¯ãã§ãããããã¢ãã«ã«å¯Ÿãããã¹ãŠã®ã¢ã¯ã·ã§ã³ã¯UIã¹ããªãŒã ããå®è¡ããå¿
èŠããããŸãã
- å€ãã®å ŽåãUIã©ã€ãã©ãªã¯ç¬èªã®æææš©éå±€ã䜿çšããããã shared_ptrã䜿çšããŠã¢ãã«ãä¿åããããšã¯ã§ããŸããã ãããã£ãŠã track / track_foreignã«ãããã©ãŒã«ã¹ã¯ããã§ã¯æ©èœããŸããããããã¯ä»ã§ã¯äž»ãªããšã§ã¯ãªãã®ã§ããã¹ãŠãæ£åžžã§ãããµããããŸããã
class MediaUiModel : public UiModel<MediaUiModelRow> { private: boost::io_service& _uiThread; boost::signals2::connection _connection; public: MediaUiModel(boost::io_service& uiThread, const MediaScanner& scanner) : _uiThread(uiThread) { std::lock_guard<std::recursive_mutex> l(scanner.GetMutex()); scanner.OnMediaFound.connect([&](const MediaPtr& m) { this->MediaHandler(m); }); for (auto&& m : scanner.GetMedia()) AppendRow(MediaUiModelRow(m)) } ~MediaUiModel() { _connection.disconnect(); } private:
åã®åé¡ã«å ããŠããã1ã€ãããŸãã ã·ã°ãã«ãããªã¬ãŒããããã³ã«ããã³ãã©ãŒãUIã¹ããªãŒã ã«è»¢éããŸãã ããæç¹ã§ã¢ãã«ãåé€ãããšïŒããšãã°ãGalleryã¢ããªã±ãŒã·ã§ã³ãé¢ããå ŽåïŒããããã®ãã³ãã©ãŒã¯ãã¹ãŠãåŸã§ããããªããžã§ã¯ãã«å°éããŸãã ãããŠåã³ç§ã
Qtã®ãœãªã¥ãŒã·ã§ã³
åãæ©èœãæã€ãã¹ãŠåã
deleteLater ã
Boostã®ãœãªã¥ãŒã·ã§ã³:: Signals2
幞éã§ãUIãã¬ãŒã ã¯ãŒã¯ã§
deleteLaterã¢ãã«ãæå®ã§ããå Žåã¯ãä¿åãããŸãã æåã«ã¢ãã«ãã·ã°ãã«ããåæãã次ã«
deleteLaterãåŒã³åºããããªãã¯ã¡ãœãããäœæããã ãã§ãQtãšåãåäœãåŸãããŸãã 確ãã«ãåã®åé¡ã解決ããå¿
èŠããããŸãã ãããè¡ãã«ã¯ãä¿¡å·ããµãã¹ã¯ã©ã€ãããã¢ãã«å
ã«
shared_ptrã¢ãã«ãäœæããå¯èœæ§ããããŸãã ã³ãŒãã¯ããã»ã©å°ãããããŸããããããã¯æè¡ã®åé¡ã§ãã
éãæªããUIãã¬ãŒã ã¯ãŒã¯ã§ã¢ãã«ãåé€ããå¿
èŠãããå Žåã¯ã
life_tokenãäœæããŸãã
ããšãã°ã次ã®ãããªãã®ã§ãïŒç²ããŠããå Žåã¯èªãŸãªãããšããå§ãããŸãïŒã template < typename Signature_ > class AsyncToUiHandlerWrapper { private: boost::io_service& _uiThread; std::function<Signature_> _realHandler; bool _released; mutable std::mutex _mutex; public: AsyncToUiHandlerWrapper(boost::io_service& uiThread, std::function<Signature_> realHandler) : _uiThread(uiThread), _realHandler(realHandler), _released(false) { } void Release() { std::lock_guard<std::mutex> l(_mutex); _released = true; } template < typename... Args_ > static void AsyncHandler(const std::weak_ptr<AsyncToUiHandlerWrapper>& selfWeak, Args_&&... args) { auto self = selfWeak.lock(); std::lock_guard<std::mutex> l(self->_mutex); if (!self->_released)
ãã®ã³ãŒãã«ã€ããŠã¯ã³ã¡ã³ãããŸããããå°ãæ²ããŸãããã
ããè¯ãæ¹æ³ã¯ïŒ
ãšãŠãç°¡åã§ãã ãŸããã¿ã¹ã¯ãã¥ãŒãšããŠã¹ã¬ããã®ã€ã³ã¿ãŒãã§ã€ã¹ãäœæããŸãã
struct task_executor { virtual ~task_executor() { } virtual void add_task(const std::function<void()>& task) = 0; };
次ã«ãã·ã°ãã«ã«ãªãŒããŒããŒãããã
æ¥ç¶ã¡ãœãããäœæããã¹ããªãŒã ãåãå
¥ããŸãã
signal_connection connect(const std::shared_ptr<task_executor>& worker, std::function<Signature> handler);
ãã®ã¡ãœããã§ã¯ã
_handlersã³ã¬ã¯ã·ã§ã³å
ã®ãã³ãã©ãŒã«ã©ãããŒãé
眮ããŸããããã¯ãåŒã³åºããããšããã³ãã©ãŒãšå¯Ÿå¿ãã
life_token ::ãã§ãã«ãŒã®ãã¢ãç®çã®ã¹ããªãŒã ã«è»¢éããŸãã æçµã¹ã¬ããã§å®éã®ãã³ãã©ãŒãåŒã³åºãã«ã¯ãåãšåãããã«
execution_guardã䜿çšããŸãã
ãããã£ãŠã
disconnectã¡ãœããã¯ããšããããã·ã°ãã«ããåæããåŸãéåæãã³ãã©ãŒãåŒã³åºãããªãããšãä¿èšŒããŸãã
ããã§ã¯ãã©ãããŒãšãªãŒããŒããŒãããã
æ¥ç¶ã¡ãœããã®ã³ãŒãã¯æäŸããŸããã ç§ã¯ãã®èããæ確ã ãšæããŸãã
ã¢ãã«ã³ãŒãã¯éåžžã«åçŽã«ãªããŸãã
class MediaUiModel : public UiModel<MediaUiModelRow> { private: signal_connection _connection; public: MediaUiModel(const std::shared_ptr<task_executor>& uiThread, const MediaScanner& scanner) { _connection = scanner.OnMediaFound.connect(uiThread, [&](const MediaPtr& m) { this->AppendRow(MediaUiModelRow(m)); }); } ~MediaUiModel() { _connection.reset(); } };
ããã§ã¯ã
AppendRowã¡ãœããã¯UIã¹ã¬ããã§å³å¯ã«åŒã³åºãããåæãããŸã§ã®ã¿åŒã³åºãããŸãã
ãŸãšãããš
ãã®ãããä¿¡å·ã䜿çšããŠããç°¡åãªã³ãŒããäœæã§ããããã«ãã3ã€ã®éèŠãªããšããããŸãã
- ããã¥ã¬ãŒã¿ãŒã«ãããä¿¡å·ã«æ¥ç¶ããªããçŸåšã®ç¶æ
ãç°¡åã«ååŸã§ããŸã
- åæãããã¯ã¡ãœããã䜿çšãããšããªããžã§ã¯ããç¬èªã®ãã¹ãã©ã¯ã¿ã§ãµãã¹ã¯ã©ã€ã解é€ã§ããŸãã
- åã®é
ç®ãéåæãã³ãã©ãŒã«åœãŠã¯ãŸãããã«ã åæã¯ãã¹ããªãŒã ãã¥ãŒã«æ¢ã«ååšããåŒã³åºãããç¡é¢ä¿ããšããŠããŒã¯ããå¿
èŠããããŸãã
ãã¡ãããç§ãããã«æã£ãŠããä¿¡å·ã³ãŒãã¯éåžžã«ã·ã³ãã«ã§åå§çã§ãããéåžžã«éãåäœããŸããã ç§ã®ç®æšã¯ãä»æ¥ã®æ¯é
çãªã¢ãããŒããããé
åçãªä»£æ¿ã¢ãããŒãã«ã€ããŠè©±ãããšã§ããã å®éã«ã¯ãããããã¹ãŠã®ããšãã¯ããã«å¹ççã«èšè¿°ã§ããŸãã
ç§ãã¡ã¯ãããžã§ã¯ãã§ãã®ã¢ãããŒããçŽ5幎é䜿çšããŠãããéåžžã«æºè¶³ããŠããŸãã
ããã«äœ¿ãã
ç§ã¯ãC ++ 11ããŒãããæžãçŽããŠãç§ãã¡ãæã£ãŠããã·ã°ãã«ãæ¹åããå®è£
ã®é·ãéæ¹åãã䟡å€ã®ãã£ãéšåãæ¹åããŸããã
å¥åº·ã«äœ¿çšïŒ
https :
//github.com/koplyarov/wigwagããFAQ
redditãšTwitterã§ã®äººã
ã®åå¿ããå€æãããšãåºæ¬çã«3ã€ã®è³ªåãå
šå¡ã«é¢ä¿ããŠããŸãã
QïŒããã«ãåãã³ãã©ãŒã®åŒã³åºãã§life_tokenããããã¯ããå¿
èŠããããŸãã é
ãã§ããããïŒ
AïŒå¥åŠãªããšã«ããããã ãã¥ãŒããã¯ã¹ã®ä»£ããã«ã¢ãããã¯å€æ°ã䜿çšã§ããŸãããã³ãã©ãŒãå®è¡ãããæç¹ã§ãŸã
åæåŒã³åºãããã£ãå Žåã¯ã
std :: condition_variableã§åŸ
æ©ã
ãŸã ã
ãã®çµæããŸã£ããéã«ãªããŸãïŒtrack / track_foreignïŒweak_ptrã³ã¬ã¯ã·ã§ã³ãæäœããå¿
èŠããããŸãïŒã®åœ¢åŒã®ãªãŒããŒããããæ¬ èœããŠããããããã®å®è£
ã¯ã¡ã¢ãª:: speed2ãã¡ã¢ãªãšé床ã§ã¯ããã«æ®ããQtãããåªããŠããŸãããã³ãããŒã¯ã¯ããã«ãããŸããQïŒãããã¯ã®åææ¹æ³ã«ãããããããã¯ã¯ãããŸããïŒAïŒã¯ãããããããã¯ã¯ãããŒã¹ããQtãããç°¡åã«ååŸã§ããŸããç§ã®æèŠã§ã¯ãããã¯ä¿¡å·ã䜿çšããããã®ããã·ã³ãã«ãªã³ãŒããšåœŒãã®ä»äºã®ããéãé床ã§å ±ãããŸããããã«ã誰ã誰ããã©ããŒããŠãããã泚ææ·±ãç£èŠããå Žåããã®ãããªç¶æ³ã¯äŸå€ã§ããå¯èœæ§ãé«ããªããŸãããã¡ããããããããã¯ããã£ããããŠä¿®åŸ©ããå¿
èŠããããŸãã Linuxã§ã¯ãããã«Helgrindããå§ãããŸãã Windowsã®å ŽåãIntel InspectorãšCHESSã«ãã£ãŠ2åéã®Googleæ€çŽ¢ãæäŸãããŸããäœããã®çç±ã§äžèšã®ãããã賌å
¥ã§ããªãå ŽåïŒããšãã°ããã©ãããã©ãŒã ã«helgrindãããçš®ã®éçãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ãå®è¡ããããã®ååãªã¡ã¢ãªããªãå ŽåïŒããã®ïŒåã³ãåçŽåãããïŒmutexã¯ã©ã¹ã®åœ¢åŒã®æŸèæããããŸãïŒ class mutex { private: std::timed_mutex _m; public: void lock() { if (_m.try_lock()) return; while (!_m.try_lock_for(std::chrono::seconds(10))) Logger::Warning() << "Could not lock mutex " << (void*)this << " for a long time:\n" << get_backtrace_string(); }
Visual StudioãšGCCã®äž¡æ¹ã«ãã³ãŒãã§ããã¯ãã¬ãŒã¹ãååŸããæ©èœããããŸããããã«ãåªããlibunwindããããŸãããã®ã¢ãããŒãã䜿çšãããšããããããã¯ã®ã»ãšãã©ãQAã«ãã£ãŠãã£ããããããã°ãäžç®ã§èŠããšããã¹ãŠããããã¯ãããå ŽæãããããŸããä¿®çãå¿
èŠãªã ãã§ããQïŒ 1ã€ã®ãã¥ãŒããã¯ã¹ãè€æ°ã®ä¿¡å·ã«äœ¿çšã§ããŸããïŒç§ãæãæ¹æ³ã§äŸå€ãåŠçããããšã¯å¯èœã§ããïŒåæã䜿çšãããé«éã®ã·ã³ã°ã«ã¹ã¬ããä¿¡å·ãååŸããããšã¯å¯èœã§ããïŒAïŒã§ãããã§ãããã§ãããããã«ã¯ãã³ãã¬ãŒãæŠç¥ããããŸãã詳现ã¯ããã¥ã¡ã³ããã芧ãã ããã