mirror of
https://github.com/pocoproject/poco.git
synced 2025-03-04 07:27:23 +01:00
fix(AsyncChannel): race condition in AsyncChannel close/log #1039
This commit is contained in:
parent
fbdb6120aa
commit
2bd71b4ea4
@ -25,6 +25,7 @@
|
||||
#include "Poco/Runnable.h"
|
||||
#include "Poco/AutoPtr.h"
|
||||
#include "Poco/NotificationQueue.h"
|
||||
#include <atomic>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@ -110,6 +111,7 @@ private:
|
||||
NotificationQueue _queue;
|
||||
std::size_t _queueSize = 0;
|
||||
std::size_t _dropCount = 0;
|
||||
std::atomic<bool> _closed;
|
||||
};
|
||||
|
||||
|
||||
|
@ -51,7 +51,8 @@ private:
|
||||
|
||||
AsyncChannel::AsyncChannel(Channel::Ptr pChannel, Thread::Priority prio):
|
||||
_pChannel(pChannel),
|
||||
_thread("AsyncChannel")
|
||||
_thread("AsyncChannel"),
|
||||
_closed(false)
|
||||
{
|
||||
_thread.setPriority(prio);
|
||||
}
|
||||
@ -94,21 +95,25 @@ void AsyncChannel::open()
|
||||
|
||||
void AsyncChannel::close()
|
||||
{
|
||||
if (_thread.isRunning())
|
||||
if (!_closed.exchange(true))
|
||||
{
|
||||
while (!_queue.empty()) Thread::sleep(100);
|
||||
|
||||
do
|
||||
if (_thread.isRunning())
|
||||
{
|
||||
_queue.wakeUpAll();
|
||||
while (!_queue.empty()) Thread::sleep(100);
|
||||
|
||||
do
|
||||
{
|
||||
_queue.wakeUpAll();
|
||||
}
|
||||
while (!_thread.tryJoin(100));
|
||||
}
|
||||
while (!_thread.tryJoin(100));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AsyncChannel::log(const Message& msg)
|
||||
{
|
||||
if (_closed) return;
|
||||
if (_queueSize != 0 && _queue.size() >= _queueSize)
|
||||
{
|
||||
++_dropCount;
|
||||
|
@ -31,6 +31,8 @@ using Poco::StreamChannel;
|
||||
using Poco::Formatter;
|
||||
using Poco::Message;
|
||||
using Poco::AutoPtr;
|
||||
using Poco::Thread;
|
||||
using Poco::Runnable;
|
||||
|
||||
|
||||
class SimpleFormatter: public Formatter
|
||||
@ -45,6 +47,32 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class LogRunnable : public Runnable
|
||||
{
|
||||
public:
|
||||
LogRunnable(AutoPtr<AsyncChannel> pAsync):
|
||||
_pAsync(pAsync),
|
||||
_stop(false)
|
||||
{
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
Message msg;
|
||||
while (!_stop) _pAsync->log(msg);
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
_stop = true;
|
||||
}
|
||||
|
||||
private:
|
||||
AutoPtr<AsyncChannel> _pAsync;
|
||||
std::atomic<bool> _stop;
|
||||
};
|
||||
|
||||
|
||||
ChannelTest::ChannelTest(const std::string& name): CppUnit::TestCase(name)
|
||||
{
|
||||
}
|
||||
@ -71,12 +99,17 @@ void ChannelTest::testAsync()
|
||||
{
|
||||
AutoPtr<TestChannel> pChannel = new TestChannel;
|
||||
AutoPtr<AsyncChannel> pAsync = new AsyncChannel(pChannel);
|
||||
LogRunnable lr(pAsync);
|
||||
pAsync->open();
|
||||
Thread t;
|
||||
t.start(lr);
|
||||
Message msg;
|
||||
pAsync->log(msg);
|
||||
pAsync->log(msg);
|
||||
pAsync->close();
|
||||
assertTrue (pChannel->list().size() == 2);
|
||||
lr.stop();
|
||||
t.join();
|
||||
assertTrue (pChannel->list().size() >= 2);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user