In order to avoid computations in GUI thread on button click I'm trying to run it in separate thread.
As soon as I want to have ability to monitor progress my code is based on this source.
So, my code is:
futureWatcher.setFuture(QtConcurrent::mapped(library_pool.cbegin(), library_pool.cend(), util->loadFilesInLibrary(library_pool)));
futureWatcher.waitForFinished();
table = QFuture::result();
Which is quite similar to the given sorce from qt docs, but it gives corresponding errors:
C2893: Failed to specialize function template 'QFuture<QtPrivate::MapResultType<void,MapFunctor>::ResultType> QtConcurrent::mapped(Iterator,Iterator,MapFunctor)'
C2780: 'QFuture<QtPrivate::MapResultType<void,MapFunctor>::ResultType> QtConcurrent::mapped(const Sequence &,MapFunctor)': expects 2 arguments - 3 provided
C2955: 'QFuture': use of class template requires template argument list
'QFuture<T>::result': illegal call of non-static member function
So, how do I properly populate worker thread(s) with function from non-gui class in button_clicked slot without making GUI hand?
UPD
Well, I've succeeded with compiling code for now and this is how it works:
futureWatcher.setFuture(QtConcurrent::run(&this->util, &Utils::loadFilesInLibrary, library_pool.at(0)));
futureWatcher.waitForFinished();
library_pool = future.result();
But button click still results to error in runtime:
My function which I'm trying to run generates no widgets, so the reason of this message is unclear.
I've read couple questions (like this) where all the code stated to work but it resides only in main() which is far from my needs. So, again, how do I start it from GUI thread?
You can use non-static members with QtConcurrent methods with the help of a wrapper. There is more discussion about it at Qt's Forums. Here's another similar question asking about how to use the wrapper.
struct AddWrapper {
Utils *utils = nullptr;
typedef MyType result_type;
AddWrapper(Util *u): instance(u) {};
MyType operator()(const MyType &t) const {
return instance->longMethod(t);
}
}
Utils *foo = new Utils();
AddWrapper wrapper(foo);
QFuture<MyType> results = QtConcurrent::mapped(myList, wrapper);
Related
I have a question regarding ROS2 messages or possibly just standard C++, maybe one of you have tried something similar before, or can tell me that what I am trying to accomplish won't work.
What I'm trying to create is a library that I can use to quickly create a ROS2 Node, dynamically add publishers and/or subscribers, depending on the situation, before starting the node.
The problem I'm facing is that ROS2 uses message types like std_msgs::msg::String. Example source can be found on github.
The source uses the following code to create a subscriber:
subscription_ = this->create_subscription<std_msgs::msg::String>("topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
I would like to create a function that can create a subscriber using a given message type i.e.:
void createListener(std::string topicName, 'messagetype')
{
auto subscription_ = this->create_subscription<'messagetype'>(topicname, 10, [this]{}, this, _1));
//adding the created subscriber to a list is already done
}
This would allow me to use the same function while still being able to use different messages like:
nav_msgs::msg::Path
geometry_msgs::msg::Point
without having to create a new function for every message type.
I can't seem to find the template type that is used in the create_subscribtion<>() function, all I can find is that each message creates its own type.
std_msgs::msg::String would return the std_msgs::msg::String_<std::allocator<void>> type.
Is there a way that i can make this work?
You could use templates here right, by doing the following:
template <typename MsgType>
void createListener(std::string topicName)
{
auto subscription_ = this->create_subscription<MsgType>(topicname, 10, [this]{}, this, _1));
//adding the created subscriber to a list is already done
}
This function can then be called, for example by:
createListener<nav_msgs::msg::Path>("topicName")
I'm trying to subscribe to different topics in ROS (one for every vehicle that pops up) using the same callback for all of them. The idea is that boost::bind will pass the topic name as an additional argument so I know which vehicle I should access in the callback.
The problem is that, even though I've gone through multiple questions on the topic, none of the solutions seem to work.
Basically, I have the following class VOBase containing a std::map<std::string, VOAgent*> agents_ with a member function as follows:
void VOBase::callback_agentState(const custom_msgs::VState::ConstPtr& vStateMsg,
std::string topic) {
// [...] regex to find agent name from topic string
std::string agent_name = match.str();
// [...] Check if agent name exists, else throw exception
// Process message
agents_[agent_name]->pos_ = vStateMsg->pose.position; // etc.
}
Which I'm calling through this subscription:
void VOBase::callback_agentList(const custom_msgs::VehicleList& vehListMsg) {
// [...] New agent/vehicle found: process vehListMsg and get agent_name string
// Subscribe to VState
topic_name = agent_name + "/state_estimate";
subscribers_[topic_name] = nodeHandlePtr->subscribe<custom_msgs::VState>(topic_name, 1,
std::bind(&VOBase::callback_agentState, this, _1, topic_name));
}
However, I'm getting a template argument deduction/substitution failed with all the candidates and this error:
mismatched types ‘std::reference_wrapper<_Tp>’ and ‘VO::VOBase*’
typename add_cv<_Functor>::type&>::type>()(
I've tested a number of the solutions out there, e.g. using std::ref(this) to get a std::reference_wrapper<_Tp> instead of a VO::VOBase* (the reference doesn't survive though: use of deleted function), using boost::bind instead of std::bind (but it should be all the same since C++11), with and without the ...::ConstPtr for the ROS message in the callback function arguments (and in the subscribe<acl_msgs::ViconState::ConstPtr>, etc. So I'm just juggling with partial solutions and their permutations here...
Any clues?
I haven't looked into the specifics of the code you show (it's hard to figure out the information not shown and deduce what's required).
However, last time I helped someone with ROS subscriptions and the type-deduction, it was apparent that the handler should take a shared_ptr to the message. This might help you get started seeing a solution:
Error using boost::bind for subscribe callback
I'm trying to connect a timeout handler to my gtkmm code as shown in gtkmm book. However, my particular on_timeout() function doesn't need any arguments, and I'm struggling to properly create a sigc::slot object to pass to the connect function, as I encounter the following error (among others):
error: no matching function for call to ‘bind(sigc::bound_mem_functor0<bool, DerivedWindow>)
and several
candidate expects 2 arguments, 1 provided
referring to sigc::bind. How I am calling both functions:
_timeout_slot = sigc::bind(sigc::mem_fun(*this,&DerivedWindow::on_timeout));
_connection = Glib::signal_timeout().connect(_timeout_slot,timeout_value);
I'm doing this on a class DerivedWindow derived from Gtk::Window. What exactly am I doing wrong? Do I need to use sigc::bind and sigc::mem_func if I don't require any arguments?
You don't need sigc::bind here since you are not binding any additional arguments to the slot (dealing with dereferencing the member function pointer for this is already taken care of by sigc::mem_fun). So, this is sufficient:
_timeout_slot = sigc::mem_fun(*this, &MyWindow::on_timeout)
_connection = Glib::signal_timeout().connect(_timeout_slot, timeout_value);
A quick tip: if you can use C++11, you can just pass lambdas as arguments to connect, which makes things more readable:
_connection = Glib::signal_timeout().connect([this]{ return on_timeout(); }, timeout_value);
For this to work, you may need to add
namespace sigc{
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
}
Also, if you want to connect to signals of a class instance (say a Gtk::Button* btn), you can make things even more compact by defining a macro
#define CONNECT(src, signal, ...) (src)->signal_##signal().connect(__VA_ARGS__)
which then allows you to write
CONNECT(btn, clicked, [this]{ btn_clicked_slot(); });
I have a TcpDevice class which encapsulates a TCP connection, which has an onRemoteDisconnect method which gets called whenever the remote end hangs up. Then, there's a SessionManager object which creates TcpSession objects which take a TcpDevice as a communication channel and inserts them in an internal pointer container for the application to use. In case any of the managed TcpSessions should end, I would like the SessionManager instance to be notified about it and then remove the corresponding session from the container, freeing up the resources associated with it.
I found my problem to be very similar to this question:
Object delete itself from container
but since he has a thread for checking the connections state, it gets a little different from mine and the way I intended to solve it using boost::signals, so I decided to go for a new question geared towards it - I apologize if it's the wrong way to do it... I'm still getting the feel on how to properly use S.O. :)
Since I'm kind of familiar with QT signals/slots, I found boost::signals offers a similar mechanism (I'm already using boost::asio and have no QT in this project), so I decided to implement a remoteDeviceDisconnected signal to be emitted by TcpDevice's onRemoteDisconnect, and for which I would have a slot in SessionManager, which would then delete the disconnected session and device from the container.
To initially try it out I declared the signal as a public member of TcpDevice in tcpdevice.hpp:
class TcpDevice
{
(...)
public:
boost::signal <void ()> remoteDeviceDisconnected;
(...)
}
Then I emitted it from TcpDevice's onRemoteDisconnect method like this:
remoteDeviceDisconnected();
Now, is there any way to connect this signal to my SessionManager slot from inside session manager? I tried this:
unsigned int SessionManager::createSession(TcpDevice* device)
{
unsigned int session_id = session_counter++;
boost::mutex::scoped_lock lock(sessions_mutex);
sessions.push_back(new TcpSession(device, session_id));
device->remoteDeviceDisconnected.connect(boost::bind(&SessionManager::removeDeadSessionSlot, this));
return session_id;
}
It compiles fine but at link time it complains of multiple definitions of remoteDeviceDisconnected in several object code files:
tcpsession.cpp.o:(.bss+0x0): multiple definition of `remoteDeviceDisconnected'
tcpdevice.cpp.o: (.bss+0x0): first defined here
sessionmanager.cpp.o:(.bss+0x0): multiple definition of `remoteDeviceDisconnected'
tcpdevice.cpp.o: (.bss+0x0): first defined here
I found this strange, since I didn't redefine the signal anywhere, but just used it at the createSession method above.
Any tips would be greatly appreciated! Thank you!
My bad! Like we all should expect, the linker was right... there was indeed a second definition, I just couldn't spot it right away because it wasn't defined by any of my classes, but just "floating" around one of my .cpp files, like those found on boost::signals examples.
Just for the record, the initial idea worked like a charm: when a given TcpDevice gets disconnected from the remote end, it emits the remoteDeviceDisconnected signal, which is then caught by the SessionManager object which holds the TcpSession instance that points to that TcpDevice. Once notified, SessionManager's method removeDeadSessionSlot gets executed, iterating through the sessions ptr_list container and removing the one which was disconnected:
void SessionManager::removeDeadSessionSlot()
{
boost::mutex::scoped_lock lock(sessions_mutex);
TcpSession_ptr_list_it it = sessions.begin();
while (it != sessions.end()) {
if (!(*it).device->isConnected())
it = sessions.erase(it);
else
++it;
}
}
Hope that may serve as a reference to somebody!
I've successfully loaded a C++ plugin using a custom plugin loader class. Each plugin has an extern "C" create_instance function that returns a new instance using "new".
A plugin is an abstract class with a few non-virtual functions and several protected variables(std::vector refList being one of them).
The plugin_loader class successfully loads and even calls a virtual method on the loaded class (namely "std::string plugin::getName()".
The main function creates an instance of "host" which contains a vector of reference counted smart pointers, refptr, to the class "plugin". Then, main creates an instance of plugin_loader which actually does the dlopen/dlsym, and creates an instance of refptr passing create_instance() to it. Finally, it passes the created refptr back to host's addPlugin function. host::addPlugin successfully calls several functions on the passed plugin instance and finally adds it to a vector<refptr<plugin> >.
The main function then subscribes to several Apple events and calls RunApplicationEventLoop(). The event callback decodes the result and then calls a function in host, host::sendToPlugin, that identifies the plugin the event is intended for and then calls the handler in the plugin. It's at this point that things stop working.
host::sendToPlugin reads the result and determines the plugin to send the event off to.
I'm using an extremely basic plugin created as a debugging plugin that returns static values for every non-void function.
Any call on any virtual function in plugin in the vector causes a bad access exception. I've tried replacing the refptrs with regular pointers and also boost::shared_ptrs and I keep getting the same exception. I know that the plugin instance is valid as I can examine the instance in Xcode's debugger and even view the items in the plugin's refList.
I think it might be a threading problem because the plugins were created in the main thread while the callback is operating in a seperate thread. I think things are still running in the main thread judging by the backtrace when the program hits the error but I don't know Apple's implementation of RunApplicationEventLoop so I can't be sure.
Any ideas as to why this is happening?
class plugin
{
public:
virtual std::string getName();
protected:
std::vector<std::string> refList;
};
and the pluginLoader class:
template<typename T> class pluginLoader
{
public: pluginLoader(std::string path);
// initializes private mPath string with path to dylib
bool open();
// opens the dylib and looks up the createInstance function. Returns true if successful, false otherwise
T * create_instance();
// Returns a new instance of T, NULL if unsuccessful
};
class host
{
public:
addPlugin(int id, plugin * plug);
sendToPlugin(); // this is the problem method
static host * me;
private:
std::vector<plugin *> plugins; // or vector<shared_ptr<plugin> > or vector<refptr<plugin> >
};
apple event code from host.cpp;
host * host::me;
pascal OSErr HandleSpeechDoneAppleEvent(const AppleEvent *theAEevt, AppleEvent *reply, SRefCon refcon) {
// this is all boilerplate taken straight from an apple sample except for the host::me->ae_callback line
OSErr status = 0;
Result result = 0;
// get the result
if (!status) {
host::me->ae_callback(result);
}
return status;
}
void host::ae_callback(Result result) {
OSErr err;
// again, boilerplate apple code
// grab information from result
if (!err)
sendToPlugin();
}
void host::sendToPlugin() {
// calling *any* method in plugin results in failure regardless of what I do
}
EDIT: This is being run on OSX 10.5.8 and I'm using GCC 4.0 with Xcode. This is not designed to be a cross platform app.
EDIT: To be clear, the plugin works up until the Apple-supplied event loop calls my callback function. When the callback function calls back into host is when things stop working. This is the problem I'm having, everything else up to that point works.
Without seeing all of your code it isn't going to be easy to work out exactly what is going wrong. Some things to look at:
Make sure that the linker isn't throwing anything away. On gcc try the compile options -Wl -E -- we use this on Linux, but don't seem to have found a need for it on the Macs.
Make sure that you're not accidentally unloading the dynamic library before you've finished with it. RAII doesn't work for unloading dynamic libraries unless you also stop exceptions at the dynamic library border.
You may want to examine our plug in library which works on Linux, Macs and Windows. The dynamic loading code (along with a load of other library stuff) is available at http://svn.felspar.com/public/fost-base/trunk/
We don't use the dlsym mechanism -- it's kind of hard to use properly (and portably). Instead we create a library of plugins by name and put what are basically factories in there. You can examine how this works by looking at the way that .so's with test suites can be dynamically loaded. An example loader is at http://svn.felspar.com/public/fost-base/trunk/fost-base/Cpp/fost-ftest/ftest.cpp and the test suite registration is in http://svn.felspar.com/public/fost-base/trunk/fost-base/Cpp/fost-test/testsuite.cpp The threadsafe_store holds the factories by name and the suite constructor registers the factory.
I completely missed the fact that I was calling dlclose in my plugin_loader's dtor and for some reason the plugins were getting destructed between the RunApplicatoinEventLoop call and the call to sendToPlugin. I removed dlclose and things work now.