job/monitor: add simple monitor adapter

This commit is contained in:
Danny Robson 2018-03-15 15:21:41 +11:00
parent 5228cecbfb
commit 0c824919de
4 changed files with 158 additions and 0 deletions

View File

@ -270,6 +270,8 @@ list (
iterator.hpp iterator.hpp
job/event.hpp job/event.hpp
job/flag.hpp job/flag.hpp
job/monitor.cpp
job/monitor.hpp
job/queue.cpp job/queue.cpp
job/queue.hpp job/queue.hpp
job/semaphore.hpp job/semaphore.hpp
@ -486,6 +488,7 @@ if (TESTS)
iterator iterator
job/event job/event
job/flag job/flag
job/monitor
job/queue job/queue
job/semaphore job/semaphore
job/spinlock job/spinlock

19
job/monitor.cpp Normal file
View File

@ -0,0 +1,19 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#include "monitor.hpp"
using util::job::monitor;

60
job/monitor.hpp Normal file
View File

@ -0,0 +1,60 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_JOB_MONITOR_HPP
#define CRUFT_UTIL_JOB_MONITOR_HPP
#include <mutex>
#include <utility>
#include <functional>
namespace util::job {
template <typename ValueT, typename MutexT = std::mutex>
class monitor {
public:
template <typename ...Args>
monitor (Args &&...args):
m_value (std::forward<Args> (args)...)
{ ; }
class proxy {
public:
proxy (MutexT &_mutex, ValueT &_value):
m_guard (_mutex),
m_value (_value)
{ ; }
ValueT* operator-> ()
{
return &m_value;
}
private:
std::lock_guard<MutexT> m_guard;
ValueT &m_value;
};
auto acquire (void) { return proxy (m_mutex, m_value); }
auto operator-> () { return acquire (); }
private:
MutexT m_mutex;
ValueT m_value;
};
};
#endif

76
test/job/monitor.cpp Normal file
View File

@ -0,0 +1,76 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#include "tap.hpp"
#include "job/monitor.hpp"
#include "job/event.hpp"
#include "job/semaphore.hpp"
#include <atomic>
#include <thread>
///////////////////////////////////////////////////////////////////////////////
// a single atomic integer wrapper that allows precise ordering of thread
// entrance and exit for exact testing of thread interleavings.
struct foo {
foo ():
enter (0),
leave (0)
{ ; }
void
inc (void) {
enter.acquire ();
++value;
leave.release ();
}
std::atomic<int> value = 0;
util::job::semaphore enter;
util::job::semaphore leave;
};
///////////////////////////////////////////////////////////////////////////////
int
main ()
{
util::TAP::logger tap;
util::job::monitor<foo> obj;
const auto &value = obj->value;
auto &enter = obj->enter;
auto &leave = obj->leave;
std::thread t1 ([&] () { obj->inc (); });
std::thread t2 ([&] () { obj->inc (); });
tap.expect_eq (value, 0, "wrapped class was left initialised");
enter.release ();
leave.acquire ();
tap.expect_eq (value, 1, "only one thread had access");
enter.release ();
leave.acquire ();
tap.expect_eq (value, 2, "second thread got access");
t1.join ();
t2.join ();
return tap.status ();
}