The following source will not compile using MSVC 12.
IMCThreadMngr.cpp
#include "IMCThreadMngr.h"
CIMCThreadMngr::CIMCThreadMngr() : mService(),
mWork(mService)
{}
CIMCThreadMngr::~CIMCThreadMngr() {};
void CIMCThreadMngr::StopManager()
{
std::cout << "Manager ceasing" << std::endl;
mService.stop();
mServicethread.join();
std::cout << "Manager ceased" << std::endl;
}
void CIMCThreadMngr::StartManager()
{
mServicethread = boost::thread(boost::bind(&boost::asio::io_service::run, &mService));
}
void CIMCThreadMngr::RegisterThread(const std::string& name, int timeout)
{
if (name.length() == 0) {
std::cout << "No thread name provided" << std::endl;
return;
}
boost::mutex::scoped_lock lock(mGroupMutex);
ThreadObject ob = ThreadObject(mService);
ob.name_ = name;
if (timeout > 0) {
ob.timeout_ = timeout;
}
else {
ob.timeout_ = 2000;
}
mThreadGroup.push_back(ob);
}
void CIMCThreadMngr::UnRegisterThread(const std::string& name)
{
if (name.length() == 0) {
std::cout << "No thread name provided" << std::endl;
return;
}
boost::mutex::scoped_lock lock(mGroupMutex);
std::vector<ThreadObject>::iterator obref;
if (FindThreadObject(name, obref)){
mThreadGroup.erase(obref);
}
}
void CIMCThreadMngr::ThreadCheckIn(const std::string& name){
if (name.length() == 0) {
std::cout << "No thread name provided" << std::endl;
return;
}
boost::mutex::scoped_lock lock(mGroupMutex);
std::vector<ThreadObject>::iterator obref;
if (FindThreadObject(name, obref)){
obref->timer_.cancel();
obref->timer_.expires_from_now(boost::posix_time::seconds(obref->timeout_));
obref->timer_.async_wait(boost::bind(&CIMCThreadMngr::TimeoutElapsed, this));
}
}
bool CIMCThreadMngr::FindThreadObject(const std::string name, std::vector<ThreadObject>::iterator& ob){
for (ob = mThreadGroup.begin(); ob != mThreadGroup.end(); ob++) {
if ((ob->name_.compare(name) == 0)) {
return true;
}
}
return false;
}
void CIMCThreadMngr::TimeoutElapsed(const boost::system::error_code& e, const std::string& name){
boost::mutex::scoped_lock lock(mGroupMutex);
if (e != boost::asio::error::operation_aborted)
{
std::cout << "Thread " << name << " did has not responded" << std::endl; // Timer was not cancelled, take necessary action.
ThreadCheckIn(name);
}
}
IMCThreadMngr.h
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/mutex.hpp>
#include <vector>
class CIMCThreadMngr {
public:
struct ThreadObject {
std::string name_;
int timeout_;
bool threadrunning_;
boost::posix_time::ptime lastupdate_;
boost::asio::deadline_timer timer_;
ThreadObject(boost::asio::io_service& service) : timer_(service)
{
timer_.expires_from_now(boost::posix_time::millisec(3000));
}
};
public:
CIMCThreadMngr();
~CIMCThreadMngr();
void StopManager();
void StartManager();
void RegisterThread(const std::string& name, int timeout);
void UnRegisterThread(const std::string& name);
void ThreadCheckIn(const std::string& name);
bool FindThreadObject(const std::string name, std::vector<ThreadObject>::iterator& ob);
void TimeoutElapsed(const boost::system::error_code& e, const std::string& name);
void TimeoutElapsed( );
private:
boost::asio::io_service mService;
boost::asio::io_service::work mWork;
boost::thread mServicethread;
std::vector<ThreadObject> mThreadGroup;
boost::mutex mGroupMutex;
};
The compiler issue I am running into is as follows
f:\boost\boost_1_57_0\boost\asio\basic_deadline_timer.hpp(510): error C2248: 'boost::asio::basic_io_object<TimerService,false>::operator =' : cannot access private member declared in class 'boost::asio::basic_io_object<TimerService,false>'
with
[
TimerService=boost::asio::deadline_timer_service<boost::posix_time::ptime,boost::asio::time_traits<boost::posix_time::ptime>>
]
f:\boost\boost_1_57_0\boost\asio\basic_io_object.hpp(164) : see declaration of 'boost::asio::basic_io_object<TimerService,false>::operator ='
with
[
TimerService=boost::asio::deadline_timer_service<boost::posix_time::ptime,boost::asio::time_traits<boost::posix_time::ptime>>
]
This diagnostic occurred in the compiler generated function 'boost::asio::basic_deadline_timer<boost::posix_time::ptime,boost::asio::time_traits<boost::posix_time::ptime>,boost::asio::deadline_timer_service<Time,TimeTraits>> &boost::asio::basic_deadline_timer<Time,TimeTraits,boost::asio::deadline_timer_service<Time,TimeTraits>>::operator =(const boost::asio::basic_deadline_timer<Time,TimeTraits,boost::asio::deadline_timer_service<Time,TimeTraits>> &)'
with
[
Time=boost::posix_time::ptime, TimeTraits=boost::asio::time_traits<boost::posix_time::ptime>
]
Hopefully the issue is something fairly straight forward, though I can't find an obvious difference between my code above, and the boost examples of deadline_timer.
boost::asio::deadline_timer
is neither copyable nor moveable (nor copy-assignable nor move-assignable). As a result, neither is CIMCThreadMgr::ThreadObject
, which means that you cannot have a std::vector<ThreadObject>
.
A simple way around this problem is to hold the deadline_timer
in a shared_ptr
, as in
struct ThreadObject {
std::string name_;
int timeout_;
bool threadrunning_;
boost::posix_time::ptime lastupdate_;
// HERE
std::shared_ptr<boost::asio::deadline_timer> timer_;
ThreadObject(boost::asio::io_service& service)
// Also HERE
: timer_(std::make_shared<boost::asio::deadline_timer>(service))
{
// -> instead of . now.
timer_->expires_from_now(boost::posix_time::millisec(3000));
}
};
If you go this route, you'll also have to replace .
with ->
where timer_
is being used:
if (FindThreadObject(name, obref)){
// vv-- HERE
obref->timer_->cancel();
obref->timer_->expires_from_now(boost::posix_time::seconds(obref->timeout_));
obref->timer_->async_wait(boost::bind(&CIMCThreadMngr::TimeoutElapsed, this));
}
It is probably possible to use a std::unique_ptr
, but that may require larger changes to your code than replacing .
with ->
in a few places (because ThreadObject
would only be moveable but not copyable).