/*
- Copyright (C) 2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2015-2021 Carl Hetherington <cth@carlh.net>
- This program is free software; you can redistribute it and/or modify
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
- This program is distributed in the hope that it will be useful,
+ DCP-o-matic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
*/
+
#ifndef DCPOMATIC_SIGNALLER_H
#define DCPOMATIC_SIGNALLER_H
+
#include "signal_manager.h"
#include <boost/thread/mutex.hpp>
-#include <boost/signals2.hpp>
+
class WrapperBase
{
public:
- WrapperBase ()
- : _valid (true)
- , _finished (false)
- {}
-
virtual ~WrapperBase () {}
/* Can be called from any thread */
}
bool finished () const {
- boost::mutex::scoped_lock lm (_mutex);
+ boost::mutex::scoped_lock lm (_mutex, boost::try_to_lock);
+ if (!lm) {
+ /* It's possible that emission of this
+ wrapper's signal causes another signal to
+ be emitted, which causes finished() on this
+ wrapper to be called (by Signaller::emit).
+ In this case, just say that the wrapper is
+ not yet finished.
+ */
+ return false;
+ }
return _finished;
}
protected:
/* Protect _valid and _finished */
mutable boost::mutex _mutex;
- bool _valid;
- bool _finished;
+ bool _valid = true;
+ bool _finished = false;
};
+
/** Helper class to manage lifetime of signals, specifically to address
* the problem where an object containing a signal is deleted before
* its signal is emitted.
class Wrapper : public WrapperBase
{
public:
- Wrapper (T signal)
+ explicit Wrapper (T signal)
: _signal (signal)
{
T _signal;
};
+
/** Parent for any class which needs to raise cross-thread signals (from non-UI
* to UI). Subclasses should call, e.g. emit (boost::bind (boost::ref (MySignal), foo, bar));
*/
/* Can be called from any thread */
virtual ~Signaller () {
boost::mutex::scoped_lock lm (_signaller_mutex);
- for (std::list<WrapperBase*>::iterator i = _wrappers.begin(); i != _wrappers.end(); ++i) {
- (*i)->invalidate ();
+ for (auto i: _wrappers) {
+ i->invalidate();
}
}
template <class T>
void emit (T signal)
{
- Wrapper<T>* w = new Wrapper<T> (signal);
+ auto w = new Wrapper<T> (signal);
if (signal_manager) {
- signal_manager->emit (boost::bind (&Wrapper<T>::signal, w));
+ signal_manager->emit (boost::bind(&Wrapper<T>::signal, w));
}
boost::mutex::scoped_lock lm (_signaller_mutex);
/* Clean up finished Wrappers */
- std::list<WrapperBase*>::iterator i = _wrappers.begin ();
+ auto i = _wrappers.begin ();
while (i != _wrappers.end ()) {
- std::list<WrapperBase*>::iterator tmp = i;
+ auto tmp = i;
++tmp;
if ((*i)->finished ()) {
delete *i;
std::list<WrapperBase*> _wrappers;
};
+
#endif