mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-26 10:32:56 +01:00
AsyncObserver (#4444)
* feat(AsyncObserver): Improve NotificationCenter speed and usability #4414 * fix(Notification): add missing header * feat(Any): add checkers for holding nullptr #4447 * feat(NotificationCenter): g++ build and refactoring #4414 * fix(Observer): compile errors on some compilers #4414 * fix(NotificationCenter): compile errors #4414 * chore(ParallelSocketAcceptor): remove unnecessary include and using from header * feat(AsyncNotificationCenter): add #4414 * test(AsyncNotificationCenter): add mixed observer types to the test #4414 * fix(AsyncNotificationCenter): hangs on program exit #4414 * fix(dev): friend not honored, temporarily make private members public * fix(AsyncNotificationCenter); remove default #4414
This commit is contained in:
committed by
GitHub
parent
30a0a06bac
commit
88be66972a
@@ -577,6 +577,7 @@
|
|||||||
<ClCompile Include="src\Ascii.cpp" />
|
<ClCompile Include="src\Ascii.cpp" />
|
||||||
<ClCompile Include="src\ASCIIEncoding.cpp" />
|
<ClCompile Include="src\ASCIIEncoding.cpp" />
|
||||||
<ClCompile Include="src\AsyncChannel.cpp" />
|
<ClCompile Include="src\AsyncChannel.cpp" />
|
||||||
|
<ClCompile Include="src\AsyncNotificationCenter.cpp" />
|
||||||
<ClCompile Include="src\AtomicCounter.cpp" />
|
<ClCompile Include="src\AtomicCounter.cpp" />
|
||||||
<ClCompile Include="src\Base32Decoder.cpp" />
|
<ClCompile Include="src\Base32Decoder.cpp" />
|
||||||
<ClCompile Include="src\Base32Encoder.cpp" />
|
<ClCompile Include="src\Base32Encoder.cpp" />
|
||||||
@@ -1493,6 +1494,7 @@
|
|||||||
<ClInclude Include="include\Poco\AccessExpireStrategy.h" />
|
<ClInclude Include="include\Poco\AccessExpireStrategy.h" />
|
||||||
<ClInclude Include="include\Poco\ActiveDispatcher.h" />
|
<ClInclude Include="include\Poco\ActiveDispatcher.h" />
|
||||||
<ClInclude Include="include\Poco\ActiveMethod.h" />
|
<ClInclude Include="include\Poco\ActiveMethod.h" />
|
||||||
|
<ClInclude Include="include\Poco\AsyncObserver.h" />
|
||||||
<ClInclude Include="include\Poco\ActiveResult.h" />
|
<ClInclude Include="include\Poco\ActiveResult.h" />
|
||||||
<ClInclude Include="include\Poco\ActiveRunnable.h" />
|
<ClInclude Include="include\Poco\ActiveRunnable.h" />
|
||||||
<ClInclude Include="include\Poco\ActiveStarter.h" />
|
<ClInclude Include="include\Poco\ActiveStarter.h" />
|
||||||
@@ -1502,6 +1504,8 @@
|
|||||||
<ClInclude Include="include\Poco\Ascii.h" />
|
<ClInclude Include="include\Poco\Ascii.h" />
|
||||||
<ClInclude Include="include\Poco\ASCIIEncoding.h" />
|
<ClInclude Include="include\Poco\ASCIIEncoding.h" />
|
||||||
<ClInclude Include="include\Poco\AsyncChannel.h" />
|
<ClInclude Include="include\Poco\AsyncChannel.h" />
|
||||||
|
<ClInclude Include="include\Poco\AsyncObserver.h" />
|
||||||
|
<ClInclude Include="include\Poco\AsyncNotificationCenter.h" />
|
||||||
<ClInclude Include="include\Poco\AtomicCounter.h" />
|
<ClInclude Include="include\Poco\AtomicCounter.h" />
|
||||||
<ClInclude Include="include\Poco\AutoPtr.h" />
|
<ClInclude Include="include\Poco\AutoPtr.h" />
|
||||||
<ClInclude Include="include\Poco\AutoReleasePool.h" />
|
<ClInclude Include="include\Poco\AutoReleasePool.h" />
|
||||||
|
|||||||
@@ -573,6 +573,9 @@
|
|||||||
<ClCompile Include="src\AbstractObserver.cpp">
|
<ClCompile Include="src\AbstractObserver.cpp">
|
||||||
<Filter>Notifications\Source Files</Filter>
|
<Filter>Notifications\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\AsyncNotificationCenter.cpp">
|
||||||
|
<Filter>Notifications\Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="src\Notification.cpp">
|
<ClCompile Include="src\Notification.cpp">
|
||||||
<Filter>Notifications\Source Files</Filter>
|
<Filter>Notifications\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -1448,6 +1451,12 @@
|
|||||||
<ClInclude Include="include\Poco\NObserver.h">
|
<ClInclude Include="include\Poco\NObserver.h">
|
||||||
<Filter>Notifications\Header Files</Filter>
|
<Filter>Notifications\Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\Poco\AsyncObserver.h">
|
||||||
|
<Filter>Notifications\Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\Poco\AsyncNotificationCenter.h">
|
||||||
|
<Filter>Notifications\Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="include\Poco\Notification.h">
|
<ClInclude Include="include\Poco\Notification.h">
|
||||||
<Filter>Notifications\Header Files</Filter>
|
<Filter>Notifications\Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|||||||
@@ -878,6 +878,7 @@
|
|||||||
<ClCompile Include="src\Ascii.cpp" />
|
<ClCompile Include="src\Ascii.cpp" />
|
||||||
<ClCompile Include="src\ASCIIEncoding.cpp" />
|
<ClCompile Include="src\ASCIIEncoding.cpp" />
|
||||||
<ClCompile Include="src\AsyncChannel.cpp" />
|
<ClCompile Include="src\AsyncChannel.cpp" />
|
||||||
|
<ClCompile Include="src\AsyncNotificationCenter.cpp" />
|
||||||
<ClCompile Include="src\AtomicCounter.cpp" />
|
<ClCompile Include="src\AtomicCounter.cpp" />
|
||||||
<ClCompile Include="src\Base32Decoder.cpp" />
|
<ClCompile Include="src\Base32Decoder.cpp" />
|
||||||
<ClCompile Include="src\Base32Encoder.cpp" />
|
<ClCompile Include="src\Base32Encoder.cpp" />
|
||||||
@@ -2109,6 +2110,8 @@
|
|||||||
<ClInclude Include="include\Poco\Ascii.h" />
|
<ClInclude Include="include\Poco\Ascii.h" />
|
||||||
<ClInclude Include="include\Poco\ASCIIEncoding.h" />
|
<ClInclude Include="include\Poco\ASCIIEncoding.h" />
|
||||||
<ClInclude Include="include\Poco\AsyncChannel.h" />
|
<ClInclude Include="include\Poco\AsyncChannel.h" />
|
||||||
|
<ClInclude Include="include\Poco\AsyncObserver.h" />
|
||||||
|
<ClInclude Include="include\Poco\AsyncNotificationCenter.h" />
|
||||||
<ClInclude Include="include\Poco\AtomicCounter.h" />
|
<ClInclude Include="include\Poco\AtomicCounter.h" />
|
||||||
<ClInclude Include="include\Poco\AutoPtr.h" />
|
<ClInclude Include="include\Poco\AutoPtr.h" />
|
||||||
<ClInclude Include="include\Poco\AutoReleasePool.h" />
|
<ClInclude Include="include\Poco\AutoReleasePool.h" />
|
||||||
|
|||||||
@@ -579,6 +579,9 @@
|
|||||||
<ClCompile Include="src\NotificationCenter.cpp">
|
<ClCompile Include="src\NotificationCenter.cpp">
|
||||||
<Filter>Notifications\Source Files</Filter>
|
<Filter>Notifications\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\AsyncNotificationCenter.cpp">
|
||||||
|
<Filter>Notifications\Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="src\NotificationQueue.cpp">
|
<ClCompile Include="src\NotificationQueue.cpp">
|
||||||
<Filter>Notifications\Source Files</Filter>
|
<Filter>Notifications\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -1447,6 +1450,12 @@
|
|||||||
<ClInclude Include="include\Poco\AbstractObserver.h">
|
<ClInclude Include="include\Poco\AbstractObserver.h">
|
||||||
<Filter>Notifications\Header Files</Filter>
|
<Filter>Notifications\Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\Poco\AsyncObserver.h">
|
||||||
|
<Filter>Notifications\Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\Poco\AsyncNotificationCenter.h">
|
||||||
|
<Filter>Notifications\Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="include\Poco\NObserver.h">
|
<ClInclude Include="include\Poco\NObserver.h">
|
||||||
<Filter>Notifications\Header Files</Filter>
|
<Filter>Notifications\Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
include $(POCO_BASE)/build/rules/global
|
include $(POCO_BASE)/build/rules/global
|
||||||
|
|
||||||
objects = ArchiveStrategy Ascii ASCIIEncoding AsyncChannel ActiveThreadPool\
|
objects = ArchiveStrategy Ascii ASCIIEncoding AsyncChannel AsyncNotificationCenter ActiveThreadPool\
|
||||||
Base32Decoder Base32Encoder Base64Decoder Base64Encoder \
|
Base32Decoder Base32Encoder Base64Decoder Base64Encoder \
|
||||||
BinaryReader BinaryWriter Bugcheck ByteOrder Channel Checksum Clock Configurable ConsoleChannel \
|
BinaryReader BinaryWriter Bugcheck ByteOrder Channel Checksum Clock Configurable ConsoleChannel \
|
||||||
Condition CountingStream DateTime LocalDateTime DateTimeFormat DateTimeFormatter DateTimeParser \
|
Condition CountingStream DateTime LocalDateTime DateTimeFormat DateTimeFormatter DateTimeParser \
|
||||||
|
|||||||
@@ -37,12 +37,42 @@ public:
|
|||||||
AbstractObserver& operator = (const AbstractObserver& observer);
|
AbstractObserver& operator = (const AbstractObserver& observer);
|
||||||
|
|
||||||
virtual void notify(Notification* pNf) const = 0;
|
virtual void notify(Notification* pNf) const = 0;
|
||||||
|
|
||||||
virtual bool equals(const AbstractObserver& observer) const = 0;
|
virtual bool equals(const AbstractObserver& observer) const = 0;
|
||||||
virtual bool accepts(Notification* pNf, const char* pName = 0) const = 0;
|
|
||||||
|
[[deprecated("use `Poco::Any accepts(Notification*)` instead")]]
|
||||||
|
virtual bool accepts(Notification* pNf, const char* pName) const = 0;
|
||||||
|
|
||||||
|
virtual bool accepts(const Notification::Ptr& pNf) const = 0;
|
||||||
|
|
||||||
virtual AbstractObserver* clone() const = 0;
|
virtual AbstractObserver* clone() const = 0;
|
||||||
|
|
||||||
|
virtual void start();
|
||||||
|
/// No-op.
|
||||||
|
/// This method can be implemented by inheriting classes which require
|
||||||
|
/// explicit start in order to begin processing notifications.
|
||||||
|
|
||||||
virtual void disable() = 0;
|
virtual void disable() = 0;
|
||||||
|
|
||||||
|
virtual int backlog() const;
|
||||||
|
/// Returns number of queued messages that this Observer has.
|
||||||
|
/// For non-active (synchronous) observers, always returns zero.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// inlines
|
||||||
|
//
|
||||||
|
|
||||||
|
inline void AbstractObserver::start()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline int AbstractObserver::backlog() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace Poco
|
} // namespace Poco
|
||||||
|
|
||||||
|
|||||||
@@ -24,13 +24,12 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
#define poco_any_assert(cond) do { if (!(cond)) std::abort(); } while (0)
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
|
|
||||||
class Any;
|
class Any;
|
||||||
|
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
namespace Dynamic {
|
namespace Dynamic {
|
||||||
|
|
||||||
class Var;
|
class Var;
|
||||||
@@ -409,12 +408,12 @@ ValueType* AnyCast(Any* operand)
|
|||||||
/// to the stored value.
|
/// to the stored value.
|
||||||
///
|
///
|
||||||
/// Example Usage:
|
/// Example Usage:
|
||||||
/// MyType* pTmp = AnyCast<MyType*>(pAny).
|
/// MyType* pTmp = AnyCast<MyType>(pAny).
|
||||||
/// Will return NULL if the cast fails, i.e. types don't match.
|
/// Returns nullptr if the types don't match.
|
||||||
{
|
{
|
||||||
return operand && operand->type() == typeid(ValueType)
|
return operand && operand->type() == typeid(ValueType)
|
||||||
? &static_cast<Any::Holder<ValueType>*>(operand->content())->_held
|
? &static_cast<Any::Holder<ValueType>*>(operand->content())->_held
|
||||||
: 0;
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -424,8 +423,8 @@ const ValueType* AnyCast(const Any* operand)
|
|||||||
/// to the stored value.
|
/// to the stored value.
|
||||||
///
|
///
|
||||||
/// Example Usage:
|
/// Example Usage:
|
||||||
/// const MyType* pTmp = AnyCast<MyType*>(pAny).
|
/// const MyType* pTmp = AnyCast<MyType>(pAny).
|
||||||
/// Will return NULL if the cast fails, i.e. types don't match.
|
/// Returns nullptr if the types don't match.
|
||||||
{
|
{
|
||||||
return AnyCast<ValueType>(const_cast<Any*>(operand));
|
return AnyCast<ValueType>(const_cast<Any*>(operand));
|
||||||
}
|
}
|
||||||
@@ -442,18 +441,19 @@ ValueType AnyCast(Any& operand)
|
|||||||
/// Some compilers will accept this code although a copy is returned. Use the RefAnyCast in
|
/// Some compilers will accept this code although a copy is returned. Use the RefAnyCast in
|
||||||
/// these cases.
|
/// these cases.
|
||||||
{
|
{
|
||||||
typedef typename TypeWrapper<ValueType>::TYPE NonRef;
|
using NonRef = typename TypeWrapper<ValueType>::TYPE;
|
||||||
|
|
||||||
NonRef* result = AnyCast<NonRef>(&operand);
|
NonRef* result = AnyCast<NonRef>(&operand);
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
std::string s = "RefAnyCast: Failed to convert between Any types ";
|
std::string s(__func__);
|
||||||
|
s.append(": Failed to convert between Any types "s);
|
||||||
if (operand.content())
|
if (operand.content())
|
||||||
{
|
{
|
||||||
s.append(1, '(');
|
s.append(1, '(');
|
||||||
s.append(operand.content()->type().name());
|
s.append(Poco::demangle(operand.content()->type().name()));
|
||||||
s.append(" => ");
|
s.append(" => ");
|
||||||
s.append(typeid(ValueType).name());
|
s.append(Poco::demangle<ValueType>());
|
||||||
s.append(1, ')');
|
s.append(1, ')');
|
||||||
}
|
}
|
||||||
throw BadCastException(s);
|
throw BadCastException(s);
|
||||||
@@ -473,7 +473,7 @@ ValueType AnyCast(const Any& operand)
|
|||||||
/// Some compilers will accept this code although a copy is returned. Use the RefAnyCast in
|
/// Some compilers will accept this code although a copy is returned. Use the RefAnyCast in
|
||||||
/// these cases.
|
/// these cases.
|
||||||
{
|
{
|
||||||
typedef typename TypeWrapper<ValueType>::TYPE NonRef;
|
using NonRef = typename TypeWrapper<ValueType>::TYPE;
|
||||||
|
|
||||||
return AnyCast<NonRef&>(const_cast<Any&>(operand));
|
return AnyCast<NonRef&>(const_cast<Any&>(operand));
|
||||||
}
|
}
|
||||||
@@ -489,13 +489,14 @@ const ValueType& RefAnyCast(const Any & operand)
|
|||||||
ValueType* result = AnyCast<ValueType>(const_cast<Any*>(&operand));
|
ValueType* result = AnyCast<ValueType>(const_cast<Any*>(&operand));
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
std::string s = "RefAnyCast: Failed to convert between Any types ";
|
std::string s(__func__);
|
||||||
|
s.append(": Failed to convert between Any types "s);
|
||||||
if (operand.content())
|
if (operand.content())
|
||||||
{
|
{
|
||||||
s.append(1, '(');
|
s.append(1, '(');
|
||||||
s.append(operand.content()->type().name());
|
s.append(Poco::demangle(operand.content()->type().name()));
|
||||||
s.append(" => ");
|
s.append(" => ");
|
||||||
s.append(typeid(ValueType).name());
|
s.append(Poco::demangle<ValueType>());
|
||||||
s.append(1, ')');
|
s.append(1, ')');
|
||||||
}
|
}
|
||||||
throw BadCastException(s);
|
throw BadCastException(s);
|
||||||
@@ -514,13 +515,14 @@ ValueType& RefAnyCast(Any& operand)
|
|||||||
ValueType* result = AnyCast<ValueType>(&operand);
|
ValueType* result = AnyCast<ValueType>(&operand);
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
std::string s = "RefAnyCast: Failed to convert between Any types ";
|
std::string s(__func__);
|
||||||
|
s.append(": Failed to convert between Any types "s);
|
||||||
if (operand.content())
|
if (operand.content())
|
||||||
{
|
{
|
||||||
s.append(1, '(');
|
s.append(1, '(');
|
||||||
s.append(operand.content()->type().name());
|
s.append(Poco::demangle(operand.content()->type().name()));
|
||||||
s.append(" => ");
|
s.append(" => ");
|
||||||
s.append(typeid(ValueType).name());
|
s.append(Poco::demangle<ValueType>());
|
||||||
s.append(1, ')');
|
s.append(1, ')');
|
||||||
}
|
}
|
||||||
throw BadCastException(s);
|
throw BadCastException(s);
|
||||||
@@ -553,6 +555,26 @@ const ValueType* UnsafeAnyCast(const Any* operand)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename ValueType>
|
||||||
|
bool AnyHoldsNullPtr(const Any& any)
|
||||||
|
/// Returns true if any holds a null pointer.
|
||||||
|
/// Fails to compile if `ValueType` is not a pointer.
|
||||||
|
{
|
||||||
|
poco_static_assert_ptr(ValueType);
|
||||||
|
return (AnyCast<ValueType>(any) == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename ValueType>
|
||||||
|
bool AnyHoldsNullPtr(const Any* pAny)
|
||||||
|
/// Returns true if the Any pointed to holds a null pointer.
|
||||||
|
/// Returns false if `pAny` is a null pointer.
|
||||||
|
{
|
||||||
|
if (!pAny) return false;
|
||||||
|
return (AnyHoldsNullPtr<ValueType>(*pAny));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace Poco
|
} // namespace Poco
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
77
Foundation/include/Poco/AsyncNotificationCenter.h
Normal file
77
Foundation/include/Poco/AsyncNotificationCenter.h
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
//
|
||||||
|
// AsyncNotificationCenter.h
|
||||||
|
//
|
||||||
|
// Library: Foundation
|
||||||
|
// Package: Notifications
|
||||||
|
// Module: AsyncNotificationCenter
|
||||||
|
//
|
||||||
|
// Definition of the AsyncNotificationCenter class.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||||
|
// Aleph ONE Software Engineering d.o.o.,
|
||||||
|
// and Contributors.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef Foundation_AsyncNotificationCenter_INCLUDED
|
||||||
|
#define Foundation_AsyncNotificationCenter_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include "Poco/Foundation.h"
|
||||||
|
#include "Poco/NotificationCenter.h"
|
||||||
|
#include "Poco/Thread.h"
|
||||||
|
#include "Poco/Stopwatch.h"
|
||||||
|
#include "Poco/Debugger.h"
|
||||||
|
#include "Poco/ErrorHandler.h"
|
||||||
|
#include "Poco/Format.h"
|
||||||
|
#include "Poco/RunnableAdapter.h"
|
||||||
|
#include "Poco/NotificationQueue.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Poco {
|
||||||
|
|
||||||
|
|
||||||
|
class Foundation_API AsyncNotificationCenter: public NotificationCenter
|
||||||
|
/// AsyncNotificationCenter decouples posting of notifications
|
||||||
|
/// from notifying subscribers by calling observers' notification
|
||||||
|
/// handler in a dedicated thread.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AsyncNotificationCenter();
|
||||||
|
/// Creates the AsyncNotificationCenter and starts the notifying thread.
|
||||||
|
|
||||||
|
~AsyncNotificationCenter();
|
||||||
|
/// Stops the notifying thread and destroys the AsyncNotificationCenter.
|
||||||
|
|
||||||
|
AsyncNotificationCenter& operator = (const AsyncNotificationCenter&) = delete;
|
||||||
|
AsyncNotificationCenter(const AsyncNotificationCenter&) = delete;
|
||||||
|
AsyncNotificationCenter& operator = (AsyncNotificationCenter&&) = delete;
|
||||||
|
AsyncNotificationCenter(AsyncNotificationCenter&&) = delete;
|
||||||
|
|
||||||
|
virtual void postNotification(Notification::Ptr pNotification);
|
||||||
|
/// Enqueues notification into the notification queue.
|
||||||
|
|
||||||
|
virtual int backlog() const;
|
||||||
|
/// Returns the numbner of notifications in the notification queue.
|
||||||
|
|
||||||
|
private:
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
void dequeue();
|
||||||
|
|
||||||
|
using Adapter = RunnableAdapter<AsyncNotificationCenter>;
|
||||||
|
|
||||||
|
Thread _thread;
|
||||||
|
NotificationQueue _nq;
|
||||||
|
Adapter _ra;
|
||||||
|
std::atomic<bool> _started;
|
||||||
|
std::atomic<bool> _done;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Poco
|
||||||
|
|
||||||
|
|
||||||
|
#endif // Foundation_AsyncNotificationCenter_INCLUDED
|
||||||
177
Foundation/include/Poco/AsyncObserver.h
Normal file
177
Foundation/include/Poco/AsyncObserver.h
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
//
|
||||||
|
// AsyncObserver.h
|
||||||
|
//
|
||||||
|
// Library: Foundation
|
||||||
|
// Package: Notifications
|
||||||
|
// Module: AsyncObserver
|
||||||
|
//
|
||||||
|
// Definition of the AsyncObserver class template.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||||
|
// Aleph ONE Software Engineering d.o.o.,
|
||||||
|
// and Contributors.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef Foundation_AsyncObserver_INCLUDED
|
||||||
|
#define Foundation_AsyncObserver_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include "Poco/Foundation.h"
|
||||||
|
#include "Poco/NObserver.h"
|
||||||
|
#include "Poco/Thread.h"
|
||||||
|
#include "Poco/Stopwatch.h"
|
||||||
|
#include "Poco/Debugger.h"
|
||||||
|
#include "Poco/ErrorHandler.h"
|
||||||
|
#include "Poco/Format.h"
|
||||||
|
#include "Poco/RunnableAdapter.h"
|
||||||
|
#include "Poco/NotificationQueue.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Poco {
|
||||||
|
|
||||||
|
|
||||||
|
template <class C, class N>
|
||||||
|
class AsyncObserver: public NObserver<C, N>
|
||||||
|
/// AsyncObserver notifies subscribers in a dedicated thread (as opposed
|
||||||
|
/// to (N)Observer classes, which notify subscribers synchronously).
|
||||||
|
/// In order to become active and process notifications, the start()
|
||||||
|
/// method must be called.
|
||||||
|
///
|
||||||
|
/// This class is meant to be used with the NotificationCenter only.
|
||||||
|
/// Notification processing thread can be started only once, and copying
|
||||||
|
/// should be done before `start()` is called.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Type = AsyncObserver<C, N>;
|
||||||
|
using Matcher = typename NObserver<C, N>::Matcher;
|
||||||
|
using Handler = typename NObserver<C, N>::Handler;
|
||||||
|
using NotificationPtr = typename NObserver<C, N>::NotificationPtr;
|
||||||
|
|
||||||
|
AsyncObserver() = delete;
|
||||||
|
|
||||||
|
AsyncObserver(C& object, Handler handler, Matcher matcher = nullptr):
|
||||||
|
NObserver<C, N>(object, handler, matcher),
|
||||||
|
_ra(*this, &AsyncObserver::dequeue),
|
||||||
|
_started(false),
|
||||||
|
_done(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncObserver(const AsyncObserver& observer):
|
||||||
|
NObserver<C, N>(observer),
|
||||||
|
_ra(*this, &AsyncObserver::dequeue),
|
||||||
|
_started(false),
|
||||||
|
_done(false)
|
||||||
|
{
|
||||||
|
poco_assert(observer._nq.size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
~AsyncObserver()
|
||||||
|
{
|
||||||
|
disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncObserver& operator = (const AsyncObserver& observer)
|
||||||
|
{
|
||||||
|
if (&observer != this)
|
||||||
|
{
|
||||||
|
poco_assert(observer._nq.size() == 0);
|
||||||
|
setObject(observer._pObject);
|
||||||
|
setHandler(observer._handler);
|
||||||
|
setMatcher(observer._matcher);
|
||||||
|
_started = false;
|
||||||
|
_done =false;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void notify(Notification* pNf) const
|
||||||
|
{
|
||||||
|
_nq.enqueueNotification(NotificationPtr(static_cast<N*>(pNf), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual AbstractObserver* clone() const
|
||||||
|
{
|
||||||
|
return new AsyncObserver(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void start()
|
||||||
|
{
|
||||||
|
Poco::ScopedLock l(this->mutex());
|
||||||
|
if (_started)
|
||||||
|
{
|
||||||
|
throw Poco::InvalidAccessException(
|
||||||
|
Poco::format("thread already started %s", poco_src_loc));
|
||||||
|
}
|
||||||
|
|
||||||
|
_thread.start(_ra);
|
||||||
|
Poco::Stopwatch sw;
|
||||||
|
sw.start();
|
||||||
|
while (!_started)
|
||||||
|
{
|
||||||
|
if (sw.elapsedSeconds() > 5)
|
||||||
|
throw Poco::TimeoutException(poco_src_loc);
|
||||||
|
Thread::sleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void disable()
|
||||||
|
{
|
||||||
|
if (!_started.exchange(false)) return;
|
||||||
|
_nq.wakeUpAll();
|
||||||
|
while (!_done) Thread::sleep(100);
|
||||||
|
_thread.join();
|
||||||
|
NObserver<C, N>::disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int backlog() const
|
||||||
|
{
|
||||||
|
return _nq.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void dequeue()
|
||||||
|
{
|
||||||
|
Notification::Ptr pNf;
|
||||||
|
_started = true;
|
||||||
|
_done = false;
|
||||||
|
while ((pNf = _nq.waitDequeueNotification()))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this->handle(pNf.unsafeCast<N>());
|
||||||
|
}
|
||||||
|
catch (Poco::Exception& ex)
|
||||||
|
{
|
||||||
|
Poco::ErrorHandler::handle(ex);
|
||||||
|
}
|
||||||
|
catch (std::exception& ex)
|
||||||
|
{
|
||||||
|
Poco::ErrorHandler::handle(ex);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
Poco::ErrorHandler::handle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_done = true;
|
||||||
|
_started = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
using Adapter = RunnableAdapter<AsyncObserver<C, N>>;
|
||||||
|
|
||||||
|
Thread _thread;
|
||||||
|
mutable NotificationQueue _nq;
|
||||||
|
Adapter _ra;
|
||||||
|
std::atomic<bool> _started;
|
||||||
|
std::atomic<bool> _done;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Poco
|
||||||
|
|
||||||
|
|
||||||
|
#endif // Foundation_AsyncObserver_INCLUDED
|
||||||
@@ -165,42 +165,16 @@ protected:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//
|
#define poco_static_assert(B) static_assert(B)
|
||||||
// poco_static_assert
|
|
||||||
//
|
|
||||||
// The following was ported from <boost/static_assert.hpp>
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
template <bool x>
|
#define poco_static_assert_ptr(T) \
|
||||||
struct POCO_STATIC_ASSERTION_FAILURE;
|
static_assert(std::is_pointer_v<T> || \
|
||||||
|
std::is_same_v<T, nullptr_t> || \
|
||||||
|
std::is_member_pointer_v<T> || \
|
||||||
template <>
|
std::is_member_function_pointer_v<T> || \
|
||||||
struct POCO_STATIC_ASSERTION_FAILURE<true>
|
std::is_member_object_pointer_v<T>, \
|
||||||
{
|
"not a pointer")
|
||||||
enum
|
|
||||||
{
|
|
||||||
value = 1
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template <int x>
|
|
||||||
struct poco_static_assert_test
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && (__GNUC__ == 3) && ((__GNUC_MINOR__ == 3) || (__GNUC_MINOR__ == 4))
|
|
||||||
#define poco_static_assert(B) \
|
|
||||||
typedef char POCO_JOIN(poco_static_assert_typedef_, __LINE__) \
|
|
||||||
[POCO_STATIC_ASSERTION_FAILURE<(bool) (B)>::value]
|
|
||||||
#else
|
|
||||||
#define poco_static_assert(B) \
|
|
||||||
typedef poco_static_assert_test<sizeof(POCO_STATIC_ASSERTION_FAILURE<(bool) (B)>)> \
|
|
||||||
POCO_JOIN(poco_static_assert_typedef_, __LINE__) POCO_UNUSED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Foundation_Bugcheck_INCLUDED
|
#endif // Foundation_Bugcheck_INCLUDED
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
//
|
//
|
||||||
// Library: Foundation
|
// Library: Foundation
|
||||||
// Package: Notifications
|
// Package: Notifications
|
||||||
// Module: NotificationCenter
|
// Module: NObserver
|
||||||
//
|
//
|
||||||
// Definition of the NObserver class template.
|
// Definition of the NObserver class template.
|
||||||
//
|
//
|
||||||
@@ -37,25 +37,39 @@ class NObserver: public AbstractObserver
|
|||||||
/// to use this template class.
|
/// to use this template class.
|
||||||
///
|
///
|
||||||
/// This class template is quite similar to the Observer class
|
/// This class template is quite similar to the Observer class
|
||||||
/// template. The only difference is that the NObserver
|
/// template. The differences are:
|
||||||
/// expects the callback function to accept a const AutoPtr&
|
///
|
||||||
/// instead of a plain pointer as argument, thus simplifying memory
|
/// - NObserver expects the callback function to accept a const AutoPtr&
|
||||||
/// management.
|
/// instead of a plain pointer as argument, thus simplifying memory
|
||||||
|
/// management.
|
||||||
|
///
|
||||||
|
/// - In addition to dispatching notifications based on the Notification runtime
|
||||||
|
/// type, NObserver can also notify subscribers based on the Notification name.
|
||||||
|
/// To enable this functionality, a matcher function must be provided.
|
||||||
|
/// Null matcher means no matching is performed and all notificiations
|
||||||
|
/// of the type subscribed to are dispatched.
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef AutoPtr<N> NotificationPtr;
|
using Type = NObserver<C, N>;
|
||||||
typedef void (C::*Callback)(const NotificationPtr&);
|
using NotificationPtr = AutoPtr<N>;
|
||||||
|
using Callback = void (C::*)(const NotificationPtr&);
|
||||||
|
using Handler = Callback;
|
||||||
|
using Matcher = bool (C::*)(const std::string&) const;
|
||||||
|
|
||||||
NObserver(C& object, Callback method):
|
NObserver() = delete;
|
||||||
|
|
||||||
|
NObserver(C& object, Handler method, Matcher matcher = nullptr):
|
||||||
_pObject(&object),
|
_pObject(&object),
|
||||||
_method(method)
|
_handler(method),
|
||||||
|
_matcher(matcher)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NObserver(const NObserver& observer):
|
NObserver(const NObserver& observer):
|
||||||
AbstractObserver(observer),
|
AbstractObserver(observer),
|
||||||
_pObject(observer._pObject),
|
_pObject(observer._pObject),
|
||||||
_method(observer._method)
|
_handler(observer._handler),
|
||||||
|
_matcher(observer._matcher)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,54 +82,72 @@ public:
|
|||||||
if (&observer != this)
|
if (&observer != this)
|
||||||
{
|
{
|
||||||
_pObject = observer._pObject;
|
_pObject = observer._pObject;
|
||||||
_method = observer._method;
|
_handler = observer._handler;
|
||||||
|
_matcher = observer._matcher;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void notify(Notification* pNf) const
|
virtual void notify(Notification* pNf) const
|
||||||
{
|
{
|
||||||
Poco::Mutex::ScopedLock lock(_mutex);
|
handle(NotificationPtr(static_cast<N*>(pNf), true));
|
||||||
|
|
||||||
if (_pObject)
|
|
||||||
{
|
|
||||||
N* pCastNf = dynamic_cast<N*>(pNf);
|
|
||||||
if (pCastNf)
|
|
||||||
{
|
|
||||||
NotificationPtr ptr(pCastNf, true);
|
|
||||||
(_pObject->*_method)(ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool equals(const AbstractObserver& abstractObserver) const
|
virtual bool equals(const AbstractObserver& abstractObserver) const
|
||||||
{
|
{
|
||||||
const NObserver* pObs = dynamic_cast<const NObserver*>(&abstractObserver);
|
const NObserver* pObs = dynamic_cast<const NObserver*>(&abstractObserver);
|
||||||
return pObs && pObs->_pObject == _pObject && pObs->_method == _method;
|
return pObs && pObs->_pObject == _pObject && pObs->_handler == _handler && pObs->_matcher == _matcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool accepts(Notification* pNf, const char* pName = 0) const
|
[[deprecated("use `bool accepts(const Notification::Ptr&)` instead")]]
|
||||||
|
virtual bool accepts(Notification* pNf, const char* pName) const
|
||||||
{
|
{
|
||||||
return dynamic_cast<N*>(pNf) && (!pName || pNf->name() == pName);
|
return (!pName || pNf->name() == pName) && dynamic_cast<N*>(pNf) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractObserver* clone() const
|
virtual bool accepts(const Notification::Ptr& pNf) const
|
||||||
|
{
|
||||||
|
return (match(pNf) && (pNf.template cast<N>() != nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual AbstractObserver* clone() const
|
||||||
{
|
{
|
||||||
return new NObserver(*this);
|
return new NObserver(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void disable()
|
virtual void disable()
|
||||||
{
|
{
|
||||||
Poco::Mutex::ScopedLock lock(_mutex);
|
Poco::Mutex::ScopedLock lock(_mutex);
|
||||||
|
|
||||||
_pObject = 0;
|
_pObject = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void handle(const NotificationPtr& ptr) const
|
||||||
|
{
|
||||||
|
Mutex::ScopedLock lock(_mutex);
|
||||||
|
|
||||||
|
if (_pObject)
|
||||||
|
(_pObject->*_handler)(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool match(const Notification::Ptr& ptr) const
|
||||||
|
{
|
||||||
|
Mutex::ScopedLock l(_mutex);
|
||||||
|
|
||||||
|
return _pObject && (!_matcher || (_pObject->*_matcher)(ptr->name()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Mutex& mutex() const
|
||||||
|
{
|
||||||
|
return _mutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NObserver();
|
|
||||||
|
|
||||||
C* _pObject;
|
C* _pObject;
|
||||||
Callback _method;
|
Callback _handler;
|
||||||
|
Matcher _matcher;
|
||||||
mutable Poco::Mutex _mutex;
|
mutable Poco::Mutex _mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "Poco/Mutex.h"
|
#include "Poco/Mutex.h"
|
||||||
#include "Poco/RefCountedObject.h"
|
#include "Poco/RefCountedObject.h"
|
||||||
#include "Poco/AutoPtr.h"
|
#include "Poco/AutoPtr.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
@@ -37,7 +38,7 @@ class Foundation_API Notification: public RefCountedObject
|
|||||||
public:
|
public:
|
||||||
using Ptr = AutoPtr<Notification>;
|
using Ptr = AutoPtr<Notification>;
|
||||||
|
|
||||||
Notification();
|
Notification(const std::string& name = ""s);
|
||||||
/// Creates the notification.
|
/// Creates the notification.
|
||||||
|
|
||||||
virtual std::string name() const;
|
virtual std::string name() const;
|
||||||
@@ -46,6 +47,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~Notification();
|
virtual ~Notification();
|
||||||
|
std::unique_ptr<std::string> _pName;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -79,10 +79,11 @@ class Foundation_API NotificationCenter
|
|||||||
/// }
|
/// }
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
NotificationCenter();
|
NotificationCenter();
|
||||||
/// Creates the NotificationCenter.
|
/// Creates the NotificationCenter.
|
||||||
|
|
||||||
~NotificationCenter();
|
virtual ~NotificationCenter();
|
||||||
/// Destroys the NotificationCenter.
|
/// Destroys the NotificationCenter.
|
||||||
|
|
||||||
void addObserver(const AbstractObserver& observer);
|
void addObserver(const AbstractObserver& observer);
|
||||||
@@ -99,7 +100,7 @@ public:
|
|||||||
bool hasObserver(const AbstractObserver& observer) const;
|
bool hasObserver(const AbstractObserver& observer) const;
|
||||||
/// Returns true if the observer is registered with this NotificationCenter.
|
/// Returns true if the observer is registered with this NotificationCenter.
|
||||||
|
|
||||||
void postNotification(Notification::Ptr pNotification);
|
virtual void postNotification(Notification::Ptr pNotification);
|
||||||
/// Posts a notification to the NotificationCenter.
|
/// Posts a notification to the NotificationCenter.
|
||||||
/// The NotificationCenter then delivers the notification
|
/// The NotificationCenter then delivers the notification
|
||||||
/// to all interested observers.
|
/// to all interested observers.
|
||||||
@@ -120,13 +121,29 @@ public:
|
|||||||
std::size_t countObservers() const;
|
std::size_t countObservers() const;
|
||||||
/// Returns the number of registered observers.
|
/// Returns the number of registered observers.
|
||||||
|
|
||||||
|
virtual int backlog() const;
|
||||||
|
/// Returns the sum of queued notifications
|
||||||
|
/// for all observers (applies only to asynchronous observers,
|
||||||
|
/// regular observers post notifications syncronously and
|
||||||
|
/// never have a backlog).
|
||||||
|
|
||||||
static NotificationCenter& defaultCenter();
|
static NotificationCenter& defaultCenter();
|
||||||
/// Returns a reference to the default
|
/// Returns a reference to the default
|
||||||
/// NotificationCenter.
|
/// NotificationCenter.
|
||||||
|
|
||||||
|
protected:
|
||||||
|
using AbstractObserverPtr = SharedPtr<AbstractObserver>;
|
||||||
|
using ObserverList = std::vector<AbstractObserverPtr>;
|
||||||
|
|
||||||
|
Mutex& mutex()
|
||||||
|
{
|
||||||
|
return _mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObserverList observersToNotify(const Notification::Ptr& pNotification) const;
|
||||||
|
void notifyObservers(Notification::Ptr& pNotification);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef SharedPtr<AbstractObserver> AbstractObserverPtr;
|
|
||||||
typedef std::vector<AbstractObserverPtr> ObserverList;
|
|
||||||
|
|
||||||
ObserverList _observers;
|
ObserverList _observers;
|
||||||
mutable Mutex _mutex;
|
mutable Mutex _mutex;
|
||||||
|
|||||||
@@ -74,15 +74,10 @@ public:
|
|||||||
void notify(Notification* pNf) const
|
void notify(Notification* pNf) const
|
||||||
{
|
{
|
||||||
Poco::Mutex::ScopedLock lock(_mutex);
|
Poco::Mutex::ScopedLock lock(_mutex);
|
||||||
|
|
||||||
if (_pObject)
|
if (_pObject)
|
||||||
{
|
{
|
||||||
N* pCastNf = dynamic_cast<N*>(pNf);
|
pNf->duplicate();
|
||||||
if (pCastNf)
|
(_pObject->*_method)(static_cast<N*>(pNf));
|
||||||
{
|
|
||||||
pCastNf->duplicate();
|
|
||||||
(_pObject->*_method)(pCastNf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,9 +87,15 @@ public:
|
|||||||
return pObs && pObs->_pObject == _pObject && pObs->_method == _method;
|
return pObs && pObs->_pObject == _pObject && pObs->_method == _method;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool accepts(Notification* pNf, const char* pName = 0) const
|
[[deprecated("use `bool accepts(const Notification::Ptr&)` instead")]]
|
||||||
|
bool accepts(Notification* pNf, const char* pName) const
|
||||||
{
|
{
|
||||||
return dynamic_cast<N*>(pNf) && (!pName || pNf->name() == pName);
|
return (!pName || pNf->name() == pName) && (dynamic_cast<N*>(pNf) != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accepts(const Notification::Ptr& pNf) const
|
||||||
|
{
|
||||||
|
return (pNf.cast<N>() != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractObserver* clone() const
|
AbstractObserver* clone() const
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class RunnableAdapter: public Runnable
|
|||||||
/// Usage:
|
/// Usage:
|
||||||
/// RunnableAdapter<MyClass> ra(myObject, &MyObject::doSomething));
|
/// RunnableAdapter<MyClass> ra(myObject, &MyObject::doSomething));
|
||||||
/// Thread thr;
|
/// Thread thr;
|
||||||
/// thr.Start(ra);
|
/// thr.start(ra);
|
||||||
///
|
///
|
||||||
/// For using a freestanding or static member function as a thread
|
/// For using a freestanding or static member function as a thread
|
||||||
/// target, please see the ThreadTarget class.
|
/// target, please see the ThreadTarget class.
|
||||||
|
|||||||
106
Foundation/src/AsyncNotificationCenter.cpp
Normal file
106
Foundation/src/AsyncNotificationCenter.cpp
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
//
|
||||||
|
// AsyncNotificationCenter.cpp
|
||||||
|
//
|
||||||
|
// Library: Foundation
|
||||||
|
// Package: Notifications
|
||||||
|
// Module: AsyncNotificationCenter
|
||||||
|
//
|
||||||
|
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
|
||||||
|
// Aleph ONE Software Engineering d.o.o.,
|
||||||
|
// and Contributors.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#include "Poco/AsyncNotificationCenter.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Poco {
|
||||||
|
|
||||||
|
|
||||||
|
AsyncNotificationCenter::AsyncNotificationCenter(): _ra(*this, &AsyncNotificationCenter::dequeue),
|
||||||
|
_started(false),
|
||||||
|
_done(false)
|
||||||
|
{
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AsyncNotificationCenter::~AsyncNotificationCenter()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AsyncNotificationCenter::postNotification(Notification::Ptr pNotification)
|
||||||
|
{
|
||||||
|
_nq.enqueueNotification(pNotification);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int AsyncNotificationCenter::backlog() const
|
||||||
|
{
|
||||||
|
return _nq.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AsyncNotificationCenter::start()
|
||||||
|
{
|
||||||
|
Poco::ScopedLock l(mutex());
|
||||||
|
if (_started)
|
||||||
|
{
|
||||||
|
throw Poco::InvalidAccessException(
|
||||||
|
Poco::format("thread already started %s", poco_src_loc));
|
||||||
|
}
|
||||||
|
_thread.start(_ra);
|
||||||
|
Poco::Stopwatch sw;
|
||||||
|
sw.start();
|
||||||
|
while (!_started)
|
||||||
|
{
|
||||||
|
if (sw.elapsedSeconds() > 5)
|
||||||
|
throw Poco::TimeoutException(poco_src_loc);
|
||||||
|
Thread::sleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AsyncNotificationCenter::stop()
|
||||||
|
{
|
||||||
|
if (!_started.exchange(false)) return;
|
||||||
|
_nq.wakeUpAll();
|
||||||
|
while (!_done) Thread::sleep(100);
|
||||||
|
_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AsyncNotificationCenter::dequeue()
|
||||||
|
{
|
||||||
|
Notification::Ptr pNf;
|
||||||
|
_started = true;
|
||||||
|
_done = false;
|
||||||
|
while ((pNf = _nq.waitDequeueNotification()))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
notifyObservers(pNf);
|
||||||
|
}
|
||||||
|
catch (Poco::Exception& ex)
|
||||||
|
{
|
||||||
|
Poco::ErrorHandler::handle(ex);
|
||||||
|
}
|
||||||
|
catch (std::exception& ex)
|
||||||
|
{
|
||||||
|
Poco::ErrorHandler::handle(ex);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
Poco::ErrorHandler::handle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_done = true;
|
||||||
|
_started = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Poco
|
||||||
@@ -19,7 +19,8 @@
|
|||||||
namespace Poco {
|
namespace Poco {
|
||||||
|
|
||||||
|
|
||||||
Notification::Notification()
|
Notification::Notification(const std::string& name):
|
||||||
|
_pName(name.empty() ? nullptr : new std::string(name))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ Notification::~Notification()
|
|||||||
|
|
||||||
std::string Notification::name() const
|
std::string Notification::name() const
|
||||||
{
|
{
|
||||||
return typeid(*this).name();
|
return _pName ? *_pName : typeid(*this).name();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ void NotificationCenter::addObserver(const AbstractObserver& observer)
|
|||||||
{
|
{
|
||||||
Mutex::ScopedLock lock(_mutex);
|
Mutex::ScopedLock lock(_mutex);
|
||||||
_observers.push_back(observer.clone());
|
_observers.push_back(observer.clone());
|
||||||
|
_observers.back()->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -75,17 +76,34 @@ bool NotificationCenter::hasObserver(const AbstractObserver& observer) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NotificationCenter::ObserverList NotificationCenter::observersToNotify(const Notification::Ptr& pNotification) const
|
||||||
|
{
|
||||||
|
ObserverList ret;
|
||||||
|
ScopedLock<Mutex> lock(_mutex);
|
||||||
|
for (auto& o : _observers)
|
||||||
|
{
|
||||||
|
if (o->accepts(pNotification))
|
||||||
|
ret.push_back(o);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void NotificationCenter::postNotification(Notification::Ptr pNotification)
|
void NotificationCenter::postNotification(Notification::Ptr pNotification)
|
||||||
{
|
{
|
||||||
poco_check_ptr (pNotification);
|
poco_check_ptr (pNotification);
|
||||||
|
|
||||||
ScopedLockWithUnlock<Mutex> lock(_mutex);
|
notifyObservers(pNotification);
|
||||||
ObserverList observersToNotify(_observers);
|
}
|
||||||
lock.unlock();
|
|
||||||
for (auto& p: observersToNotify)
|
|
||||||
{
|
void NotificationCenter::notifyObservers(Notification::Ptr& pNotification)
|
||||||
|
{
|
||||||
|
poco_check_ptr (pNotification);
|
||||||
|
|
||||||
|
ObserverList observers = observersToNotify(pNotification);
|
||||||
|
for (auto& p: observers)
|
||||||
p->notify(pNotification);
|
p->notify(pNotification);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -105,6 +123,20 @@ std::size_t NotificationCenter::countObservers() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int NotificationCenter::backlog() const
|
||||||
|
{
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
ScopedLockWithUnlock<Mutex> lock(_mutex);
|
||||||
|
ObserverList observersToCount(_observers);
|
||||||
|
lock.unlock();
|
||||||
|
for (auto& p : observersToCount)
|
||||||
|
cnt += p->backlog();
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
NotificationCenter& NotificationCenter::defaultCenter()
|
NotificationCenter& NotificationCenter::defaultCenter()
|
||||||
{
|
{
|
||||||
static NotificationCenter nc;
|
static NotificationCenter nc;
|
||||||
|
|||||||
@@ -334,6 +334,111 @@ void AnyTest::testAnyInt()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class A
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void f() {}
|
||||||
|
int m;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void AnyTest::testAnyPointer()
|
||||||
|
{
|
||||||
|
int i = 13;
|
||||||
|
|
||||||
|
Any a = &i;
|
||||||
|
assertTrue (a.type() == typeid(int*));
|
||||||
|
assertFalse (AnyHoldsNullPtr<int*>(a));
|
||||||
|
assertFalse (AnyHoldsNullPtr<int*>(&a));
|
||||||
|
int* p = AnyCast<int*>(&i);
|
||||||
|
assertTrue (*p == 13);
|
||||||
|
Any b = a;
|
||||||
|
assertTrue (b.type() == typeid(int*));
|
||||||
|
int* cpyI = AnyCast<int*>(b);
|
||||||
|
assertTrue (*cpyI == *p);
|
||||||
|
*cpyI = 20;
|
||||||
|
assertTrue (*cpyI == *p);
|
||||||
|
std::string* s = AnyCast<std::string>(&a);
|
||||||
|
assertTrue (s == NULL);
|
||||||
|
assertTrue (AnyCast<nullptr_t>(&a) == nullptr);
|
||||||
|
|
||||||
|
int* POCO_UNUSED tmp = AnyCast<int*>(a);
|
||||||
|
const Any c = a;
|
||||||
|
tmp = AnyCast<int*>(a);
|
||||||
|
|
||||||
|
Any nullPtr(nullptr);
|
||||||
|
assertFalse (AnyHoldsNullPtr<nullptr_t>(nullptr));
|
||||||
|
assertFalse (AnyHoldsNullPtr<void*>(0));
|
||||||
|
assertTrue (AnyHoldsNullPtr<nullptr_t>(nullPtr));
|
||||||
|
assertTrue (AnyHoldsNullPtr<nullptr_t>(&nullPtr));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AnyHoldsNullPtr<void*>(nullPtr);
|
||||||
|
fail ("AnyCast must fail", __LINE__, __FILE__);
|
||||||
|
}
|
||||||
|
catch(const Poco::BadCastException&) {}
|
||||||
|
nullPtr = &i;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
assertFalse (AnyHoldsNullPtr<nullptr_t>(nullPtr));
|
||||||
|
fail ("AnyCast must fail", __LINE__, __FILE__);
|
||||||
|
}
|
||||||
|
catch(const Poco::BadCastException&) {}
|
||||||
|
assertFalse (AnyHoldsNullPtr<int*>(nullPtr));
|
||||||
|
|
||||||
|
void* voidPtr = nullptr;
|
||||||
|
Any nullVoidPtr(voidPtr);
|
||||||
|
assertTrue (AnyHoldsNullPtr<void*>(nullVoidPtr));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AnyHoldsNullPtr<nullptr_t>(voidPtr);
|
||||||
|
fail ("AnyCast must fail", __LINE__, __FILE__);
|
||||||
|
}
|
||||||
|
catch(const Poco::BadCastException&) {}
|
||||||
|
|
||||||
|
using FP = void (AnyTest::*)();
|
||||||
|
FP fp = nullptr;
|
||||||
|
Any funcPtr(fp);
|
||||||
|
assertTrue (AnyHoldsNullPtr<FP>(funcPtr));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AnyHoldsNullPtr<FP>(voidPtr);
|
||||||
|
fail ("AnyCast must fail", __LINE__, __FILE__);
|
||||||
|
}
|
||||||
|
catch(const Poco::BadCastException&) {}
|
||||||
|
funcPtr = &AnyTest::testAnyPointer;
|
||||||
|
assertFalse (AnyHoldsNullPtr<FP>(funcPtr));
|
||||||
|
|
||||||
|
using OP = decltype(&AnyTest::_dummyObject);
|
||||||
|
OP op = nullptr;
|
||||||
|
Any objPtr(op);
|
||||||
|
assertTrue (AnyHoldsNullPtr<OP>(objPtr));
|
||||||
|
objPtr = &AnyTest::_dummyObject;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AnyHoldsNullPtr<OP>(funcPtr);
|
||||||
|
fail ("AnyCast must fail", __LINE__, __FILE__);
|
||||||
|
}
|
||||||
|
catch(const Poco::BadCastException&) {}
|
||||||
|
|
||||||
|
assertFalse (AnyHoldsNullPtr<OP>(objPtr));
|
||||||
|
|
||||||
|
using MP = decltype(&AnyTest::_dummy);
|
||||||
|
MP mp = nullptr;
|
||||||
|
Any memPtr(mp);
|
||||||
|
assertTrue (AnyHoldsNullPtr<MP>(memPtr));
|
||||||
|
memPtr = &AnyTest::_dummy;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AnyHoldsNullPtr<MP>(objPtr);
|
||||||
|
fail ("AnyCast must fail", __LINE__, __FILE__);
|
||||||
|
}
|
||||||
|
catch(const Poco::BadCastException&) {}
|
||||||
|
|
||||||
|
assertFalse (AnyHoldsNullPtr<MP>(memPtr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void AnyTest::testAnyComplexType()
|
void AnyTest::testAnyComplexType()
|
||||||
{
|
{
|
||||||
SomeClass str(13,std::string("hello"));
|
SomeClass str(13,std::string("hello"));
|
||||||
@@ -456,6 +561,7 @@ CppUnit::Test* AnyTest::suite()
|
|||||||
CppUnit_addTest(pSuite, AnyTest, testAnySwap);
|
CppUnit_addTest(pSuite, AnyTest, testAnySwap);
|
||||||
CppUnit_addTest(pSuite, AnyTest, testAnyEmptyCopy);
|
CppUnit_addTest(pSuite, AnyTest, testAnyEmptyCopy);
|
||||||
CppUnit_addTest(pSuite, AnyTest, testAnyCastToReference);
|
CppUnit_addTest(pSuite, AnyTest, testAnyCastToReference);
|
||||||
|
CppUnit_addTest(pSuite, AnyTest, testAnyPointer);
|
||||||
CppUnit_addTest(pSuite, AnyTest, testAnyInt);
|
CppUnit_addTest(pSuite, AnyTest, testAnyInt);
|
||||||
CppUnit_addTest(pSuite, AnyTest, testAnyComplexType);
|
CppUnit_addTest(pSuite, AnyTest, testAnyComplexType);
|
||||||
CppUnit_addTest(pSuite, AnyTest, testAnyVector);
|
CppUnit_addTest(pSuite, AnyTest, testAnyVector);
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
class AnyTest: public CppUnit::TestCase
|
class AnyTest: public CppUnit::TestCase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
class Dummy{};
|
||||||
|
|
||||||
AnyTest(const std::string& name);
|
AnyTest(const std::string& name);
|
||||||
~AnyTest();
|
~AnyTest();
|
||||||
|
|
||||||
@@ -33,6 +35,7 @@ public:
|
|||||||
void testAnyEmptyCopy();
|
void testAnyEmptyCopy();
|
||||||
void testAnyCastToReference();
|
void testAnyCastToReference();
|
||||||
|
|
||||||
|
void testAnyPointer();
|
||||||
void testAnyInt();
|
void testAnyInt();
|
||||||
void testAnyComplexType();
|
void testAnyComplexType();
|
||||||
void testAnyVector();
|
void testAnyVector();
|
||||||
@@ -42,6 +45,10 @@ public:
|
|||||||
void setUp();
|
void setUp();
|
||||||
void tearDown();
|
void tearDown();
|
||||||
static CppUnit::Test* suite();
|
static CppUnit::Test* suite();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int _dummy = 0;
|
||||||
|
Dummy _dummyObject;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ void FIFOEventTest::testAsyncNotifyBenchmark()
|
|||||||
assertTrue (vresult[i].data() == (i*2));
|
assertTrue (vresult[i].data() == (i*2));
|
||||||
}
|
}
|
||||||
sw.stop();
|
sw.stop();
|
||||||
times.push_back(sw.elapsed()/1000);
|
times.push_back(static_cast<int>(sw.elapsed()/1000));
|
||||||
vresult.clear();
|
vresult.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,7 +451,7 @@ void FIFOEventTest::onAsyncBench(const void* pSender, int& i)
|
|||||||
|
|
||||||
int FIFOEventTest::getCount() const
|
int FIFOEventTest::getCount() const
|
||||||
{
|
{
|
||||||
return _count;
|
return static_cast<int>(_count.load());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,24 +12,40 @@
|
|||||||
#include "CppUnit/TestCaller.h"
|
#include "CppUnit/TestCaller.h"
|
||||||
#include "CppUnit/TestSuite.h"
|
#include "CppUnit/TestSuite.h"
|
||||||
#include "Poco/NotificationCenter.h"
|
#include "Poco/NotificationCenter.h"
|
||||||
|
#include "Poco/AsyncNotificationCenter.h"
|
||||||
#include "Poco/Observer.h"
|
#include "Poco/Observer.h"
|
||||||
#include "Poco/NObserver.h"
|
#include "Poco/NObserver.h"
|
||||||
|
#include "Poco/AsyncObserver.h"
|
||||||
#include "Poco/AutoPtr.h"
|
#include "Poco/AutoPtr.h"
|
||||||
|
|
||||||
|
|
||||||
using Poco::NotificationCenter;
|
using Poco::NotificationCenter;
|
||||||
|
using Poco::AsyncNotificationCenter;
|
||||||
using Poco::Observer;
|
using Poco::Observer;
|
||||||
using Poco::NObserver;
|
using Poco::NObserver;
|
||||||
|
using Poco::AsyncObserver;
|
||||||
using Poco::Notification;
|
using Poco::Notification;
|
||||||
using Poco::AutoPtr;
|
using Poco::AutoPtr;
|
||||||
|
|
||||||
|
|
||||||
class TestNotification: public Notification
|
class TestNotification: public Notification
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
TestNotification()
|
||||||
|
{}
|
||||||
|
|
||||||
|
TestNotification(const std::string& name):
|
||||||
|
Notification(name)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
NotificationCenterTest::NotificationCenterTest(const std::string& name): CppUnit::TestCase(name)
|
NotificationCenterTest::NotificationCenterTest(const std::string& name):
|
||||||
|
CppUnit::TestCase(name),
|
||||||
|
_handle1Done(false),
|
||||||
|
_handleAuto1Done(false),
|
||||||
|
_handleAsync1Done(false),
|
||||||
|
_handleAsync2Done(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,14 +55,14 @@ NotificationCenterTest::~NotificationCenterTest()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NotificationCenterTest::test1()
|
void NotificationCenterTest::testNotificationCenter1()
|
||||||
{
|
{
|
||||||
NotificationCenter nc;
|
NotificationCenter nc;
|
||||||
nc.postNotification(new Notification);
|
nc.postNotification(new Notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NotificationCenterTest::test2()
|
void NotificationCenterTest::testNotificationCenter2()
|
||||||
{
|
{
|
||||||
NotificationCenter nc;
|
NotificationCenter nc;
|
||||||
Observer<NotificationCenterTest, Notification> o(*this, &NotificationCenterTest::handle1);
|
Observer<NotificationCenterTest, Notification> o(*this, &NotificationCenterTest::handle1);
|
||||||
@@ -64,7 +80,7 @@ void NotificationCenterTest::test2()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NotificationCenterTest::test3()
|
void NotificationCenterTest::testNotificationCenter3()
|
||||||
{
|
{
|
||||||
NotificationCenter nc;
|
NotificationCenter nc;
|
||||||
Observer<NotificationCenterTest, Notification> o1(*this, &NotificationCenterTest::handle1);
|
Observer<NotificationCenterTest, Notification> o1(*this, &NotificationCenterTest::handle1);
|
||||||
@@ -88,7 +104,7 @@ void NotificationCenterTest::test3()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NotificationCenterTest::test4()
|
void NotificationCenterTest::testNotificationCenter4()
|
||||||
{
|
{
|
||||||
NotificationCenter nc;
|
NotificationCenter nc;
|
||||||
Observer<NotificationCenterTest, Notification> o1(*this, &NotificationCenterTest::handle1);
|
Observer<NotificationCenterTest, Notification> o1(*this, &NotificationCenterTest::handle1);
|
||||||
@@ -119,7 +135,7 @@ void NotificationCenterTest::test4()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NotificationCenterTest::test5()
|
void NotificationCenterTest::testNotificationCenter5()
|
||||||
{
|
{
|
||||||
NotificationCenter nc;
|
NotificationCenter nc;
|
||||||
nc.addObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
nc.addObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||||
@@ -137,7 +153,7 @@ void NotificationCenterTest::test5()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NotificationCenterTest::testAuto()
|
void NotificationCenterTest::testNotificationCenterAuto()
|
||||||
{
|
{
|
||||||
NotificationCenter nc;
|
NotificationCenter nc;
|
||||||
nc.addObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handleAuto));
|
nc.addObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handleAuto));
|
||||||
@@ -148,7 +164,59 @@ void NotificationCenterTest::testAuto()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NotificationCenterTest::testDefaultCenter()
|
void NotificationCenterTest::testAsyncObserver()
|
||||||
|
{
|
||||||
|
using ObserverT = AsyncObserver<NotificationCenterTest, TestNotification>::Type;
|
||||||
|
|
||||||
|
NotificationCenter nc;
|
||||||
|
|
||||||
|
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||||
|
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||||
|
|
||||||
|
nc.postNotification(new TestNotification("asyncNotification"));
|
||||||
|
nc.postNotification(new TestNotification("anotherNotification"));
|
||||||
|
nc.postNotification(new Notification);
|
||||||
|
|
||||||
|
while (!_handleAsync1Done || !_handleAsync2Done)
|
||||||
|
Poco::Thread::sleep(100);
|
||||||
|
|
||||||
|
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||||
|
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||||
|
|
||||||
|
Poco::Mutex::ScopedLock l(_mutex);
|
||||||
|
assertTrue(_set.size() == 2);
|
||||||
|
assertTrue(_set.find("handleAsync1") != _set.end());
|
||||||
|
assertTrue(_set.find("handleAsync2") != _set.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NotificationCenterTest::testAsyncNotificationCenter()
|
||||||
|
{
|
||||||
|
using ObserverT = AsyncObserver<NotificationCenterTest, TestNotification>::Type;
|
||||||
|
|
||||||
|
AsyncNotificationCenter nc;
|
||||||
|
|
||||||
|
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||||
|
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||||
|
|
||||||
|
nc.postNotification(new TestNotification("asyncNotification"));
|
||||||
|
nc.postNotification(new TestNotification("anotherNotification"));
|
||||||
|
nc.postNotification(new Notification);
|
||||||
|
|
||||||
|
while (!_handleAsync1Done || !_handleAsync2Done)
|
||||||
|
Poco::Thread::sleep(100);
|
||||||
|
|
||||||
|
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||||
|
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||||
|
|
||||||
|
Poco::Mutex::ScopedLock l(_mutex);
|
||||||
|
assertTrue(_set.size() == 2);
|
||||||
|
assertTrue(_set.find("handleAsync1") != _set.end());
|
||||||
|
assertTrue(_set.find("handleAsync2") != _set.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NotificationCenterTest::testDefaultNotificationCenter()
|
||||||
{
|
{
|
||||||
NotificationCenter& nc = NotificationCenter::defaultCenter();
|
NotificationCenter& nc = NotificationCenter::defaultCenter();
|
||||||
nc.addObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
nc.addObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||||
@@ -159,11 +227,38 @@ void NotificationCenterTest::testDefaultCenter()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NotificationCenterTest::testMixedObservers()
|
||||||
|
{
|
||||||
|
using AObserverT = AsyncObserver<NotificationCenterTest, TestNotification>::Type;
|
||||||
|
|
||||||
|
AsyncNotificationCenter nc;
|
||||||
|
nc.addObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||||
|
nc.addObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handleAuto));
|
||||||
|
nc.addObserver(AObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||||
|
nc.postNotification(new Notification);
|
||||||
|
nc.postNotification(new TestNotification("asyncNotification"));
|
||||||
|
|
||||||
|
while (!_handle1Done || !_handleAuto1Done || !_handleAsync1Done)
|
||||||
|
Poco::Thread::sleep(100);
|
||||||
|
|
||||||
|
nc.removeObserver(AObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||||
|
nc.removeObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handleAuto));
|
||||||
|
nc.removeObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||||
|
Poco::Mutex::ScopedLock l(_mutex);
|
||||||
|
assertTrue (_set.size() == 3);
|
||||||
|
assertTrue (_set.find("handle1") != _set.end());
|
||||||
|
assertTrue (_set.find("handleAuto") != _set.end());
|
||||||
|
assertTrue (_set.find("handleAsync1") != _set.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void NotificationCenterTest::handle1(Poco::Notification* pNf)
|
void NotificationCenterTest::handle1(Poco::Notification* pNf)
|
||||||
{
|
{
|
||||||
|
Poco::Mutex::ScopedLock l(_mutex);
|
||||||
poco_check_ptr (pNf);
|
poco_check_ptr (pNf);
|
||||||
AutoPtr<Notification> nf = pNf;
|
AutoPtr<Notification> nf = pNf;
|
||||||
_set.insert("handle1");
|
_set.insert("handle1");
|
||||||
|
_handle1Done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -193,7 +288,31 @@ void NotificationCenterTest::handleTest(TestNotification* pNf)
|
|||||||
|
|
||||||
void NotificationCenterTest::handleAuto(const AutoPtr<Notification>& pNf)
|
void NotificationCenterTest::handleAuto(const AutoPtr<Notification>& pNf)
|
||||||
{
|
{
|
||||||
|
Poco::Mutex::ScopedLock l(_mutex);
|
||||||
_set.insert("handleAuto");
|
_set.insert("handleAuto");
|
||||||
|
_handleAuto1Done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NotificationCenterTest::handleAsync1(const AutoPtr<TestNotification>& pNf)
|
||||||
|
{
|
||||||
|
Poco::Mutex::ScopedLock l(_mutex);
|
||||||
|
_set.insert("handleAsync1");
|
||||||
|
_handleAsync1Done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NotificationCenterTest::handleAsync2(const AutoPtr<TestNotification>& pNf)
|
||||||
|
{
|
||||||
|
Poco::Mutex::ScopedLock l(_mutex);
|
||||||
|
_set.insert("handleAsync2");
|
||||||
|
_handleAsync2Done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool NotificationCenterTest::matchAsync(const std::string& name) const
|
||||||
|
{
|
||||||
|
return name.find("asyncNotification") == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -212,13 +331,16 @@ CppUnit::Test* NotificationCenterTest::suite()
|
|||||||
{
|
{
|
||||||
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("NotificationCenterTest");
|
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("NotificationCenterTest");
|
||||||
|
|
||||||
CppUnit_addTest(pSuite, NotificationCenterTest, test1);
|
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenter1);
|
||||||
CppUnit_addTest(pSuite, NotificationCenterTest, test2);
|
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenter2);
|
||||||
CppUnit_addTest(pSuite, NotificationCenterTest, test3);
|
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenter3);
|
||||||
CppUnit_addTest(pSuite, NotificationCenterTest, test4);
|
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenter4);
|
||||||
CppUnit_addTest(pSuite, NotificationCenterTest, test5);
|
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenter5);
|
||||||
CppUnit_addTest(pSuite, NotificationCenterTest, testAuto);
|
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenterAuto);
|
||||||
CppUnit_addTest(pSuite, NotificationCenterTest, testDefaultCenter);
|
CppUnit_addTest(pSuite, NotificationCenterTest, testAsyncObserver);
|
||||||
|
CppUnit_addTest(pSuite, NotificationCenterTest, testAsyncNotificationCenter);
|
||||||
|
CppUnit_addTest(pSuite, NotificationCenterTest, testDefaultNotificationCenter);
|
||||||
|
CppUnit_addTest(pSuite, NotificationCenterTest, testMixedObservers);
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "CppUnit/TestCase.h"
|
#include "CppUnit/TestCase.h"
|
||||||
#include "Poco/Notification.h"
|
#include "Poco/Notification.h"
|
||||||
#include "Poco/AutoPtr.h"
|
#include "Poco/AutoPtr.h"
|
||||||
|
#include "Poco/Mutex.h"
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
|
||||||
@@ -30,13 +31,16 @@ public:
|
|||||||
NotificationCenterTest(const std::string& name);
|
NotificationCenterTest(const std::string& name);
|
||||||
~NotificationCenterTest();
|
~NotificationCenterTest();
|
||||||
|
|
||||||
void test1();
|
void testNotificationCenter1();
|
||||||
void test2();
|
void testNotificationCenter2();
|
||||||
void test3();
|
void testNotificationCenter3();
|
||||||
void test4();
|
void testNotificationCenter4();
|
||||||
void test5();
|
void testNotificationCenter5();
|
||||||
void testAuto();
|
void testNotificationCenterAuto();
|
||||||
void testDefaultCenter();
|
void testAsyncObserver();
|
||||||
|
void testAsyncNotificationCenter();
|
||||||
|
void testDefaultNotificationCenter();
|
||||||
|
void testMixedObservers();
|
||||||
|
|
||||||
void setUp();
|
void setUp();
|
||||||
void tearDown();
|
void tearDown();
|
||||||
@@ -49,9 +53,17 @@ protected:
|
|||||||
void handle3(Poco::Notification* pNf);
|
void handle3(Poco::Notification* pNf);
|
||||||
void handleTest(TestNotification* pNf);
|
void handleTest(TestNotification* pNf);
|
||||||
void handleAuto(const Poco::AutoPtr<Poco::Notification>& pNf);
|
void handleAuto(const Poco::AutoPtr<Poco::Notification>& pNf);
|
||||||
|
void handleAsync1(const Poco::AutoPtr<TestNotification>& pNf);
|
||||||
|
void handleAsync2(const Poco::AutoPtr<TestNotification>& pNf);
|
||||||
|
bool matchAsync(const std::string& name) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::set<std::string> _set;
|
std::set<std::string> _set;
|
||||||
|
std::atomic<bool> _handle1Done;
|
||||||
|
std::atomic<bool> _handleAuto1Done;
|
||||||
|
std::atomic<bool> _handleAsync1Done;
|
||||||
|
std::atomic<bool> _handleAsync2Done;
|
||||||
|
Poco::Mutex _mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1997,12 +1997,12 @@ void VarTest::testLimitsFloat()
|
|||||||
{
|
{
|
||||||
if (std::numeric_limits<double>::max() != std::numeric_limits<float>::max())
|
if (std::numeric_limits<double>::max() != std::numeric_limits<float>::max())
|
||||||
{
|
{
|
||||||
double iMin = -1 * std::numeric_limits<float>::max();
|
constexpr double iMin = -1 * std::numeric_limits<float>::max();
|
||||||
Var da = iMin * 10;
|
Var da = iMin * 10;
|
||||||
try { float POCO_UNUSED f; f = da; fail("must throw", __LINE__, __FILE__); }
|
try { float POCO_UNUSED f; f = da; fail("must throw", __LINE__, __FILE__); }
|
||||||
catch (RangeException&) {}
|
catch (RangeException&) {}
|
||||||
|
|
||||||
double iMax = std::numeric_limits<float>::max();
|
constexpr double iMax = std::numeric_limits<float>::max();
|
||||||
da = iMax * 10;
|
da = iMax * 10;
|
||||||
try { float POCO_UNUSED f; f = da; fail("must throw", __LINE__, __FILE__); }
|
try { float POCO_UNUSED f; f = da; fail("must throw", __LINE__, __FILE__); }
|
||||||
catch (RangeException&) {}
|
catch (RangeException&) {}
|
||||||
@@ -2027,13 +2027,13 @@ void VarTest::testLimitsFloat()
|
|||||||
float f = 0.f;
|
float f = 0.f;
|
||||||
try { f = anyInt.convert<float>(); fail("must throw", __LINE__, __FILE__); }
|
try { f = anyInt.convert<float>(); fail("must throw", __LINE__, __FILE__); }
|
||||||
catch (Poco::RangeException&) {}
|
catch (Poco::RangeException&) {}
|
||||||
i = f;
|
i = static_cast<int64_t>(f);
|
||||||
assertTrue (0 == i);
|
assertTrue (0 == i);
|
||||||
|
|
||||||
double d = 0.;
|
double d = 0.;
|
||||||
try { d = anyInt.convert<double>(); fail("must throw", __LINE__, __FILE__); }
|
try { d = anyInt.convert<double>(); fail("must throw", __LINE__, __FILE__); }
|
||||||
catch (Poco::RangeException&) {}
|
catch (Poco::RangeException&) {}
|
||||||
i = d;
|
i = static_cast<int64_t>(d);
|
||||||
assertTrue (0 == i);
|
assertTrue (0 == i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user